Skip to content
winfunc
Hands-on tutorial

Verify a security fix with a regression test

A closed ticket should point to a fix and evidence. Write down the intended security property, check it in a small local test, and distinguish that result from application-level verification.

Winfunc · · 4 min read

What you will put in place

  • A runnable, harmless Node.js regression-test example.
  • Checks for rejected inputs and preserved valid behavior.
  • A closure note with revision, evidence, and remaining limits.

1. State the invariant

Describe the property the patch must preserve in one sentence. For this toy example: a preference parser accepts only an approved theme and never changes the caller’s input. This is a synthetic input-validation exercise, independent of any disclosed vulnerability.

In a real review, link that property to the affected code and the normal application path. Record the base revision and patch revision. A dependency upgrade also needs a lockfile and deployed-version check.

2. Run a small regression test

Save the following as preferences.test.mjs and run node --test preferences.test.mjs with a current supported Node.js release. It performs no network requests and writes no files. Three tests check valid input, reject an unsupported value, and preserve input ownership.

preferences.test.mjs
import test from 'node:test';
import assert from 'node:assert/strict';

function parsePreferences(input) {
  if (!input || typeof input !== 'object' || Array.isArray(input)) {
    throw new TypeError('Invalid preferences');
  }
  if (input.theme !== 'light' && input.theme !== 'dark') {
    throw new TypeError('Unsupported theme');
  }
  return { theme: input.theme };
}

test('accepts the supported themes', () => {
  for (const theme of ['light', 'dark']) {
    assert.deepEqual(parsePreferences({ theme }), { theme });
  }
});

test('rejects an unsupported theme', () => {
  assert.throws(() => parsePreferences({ theme: 'sepia' }), TypeError);
});

test('returns a new value without changing input', () => {
  const input = Object.freeze({ theme: 'dark' });
  const output = parsePreferences(input);
  assert.notEqual(output, input);
  assert.deepEqual(input, { theme: 'dark' });
});

This demonstrates a testing pattern. Passing these tests does not establish that a production application is secure. Replace the toy parser with your actual code and add representative boundary cases.

3. Check both sides of the change

An assertion must detect the behavior it claims to check. For the toy parser, temporarily changing the theme validation to accept sepia should make the rejection test fail. Restore the guard and confirm all tests pass. This is a safe local negative control, not a vulnerability reproduction.

For your real code, pair the regression case with supported inputs, relevant application tests, and a review of other callers. A source change can look correct while the deployed service still uses an older build.

  • Run the regression test and normal behavior tests on the patch revision.
  • Check error behavior and adjacent valid workflows.
  • Verify the resulting artifact and deployment revision through your normal release process.
  • Keep unresolved dependencies or excluded environments visible.

4. Write the closure note

Record what passed, where it ran, and what remains unverified. A unit test establishes behavior at a method boundary. Application or deployment verification requires separate evidence about the real path and version.

Fix verification note
Finding: __________________________
Fix commit / dependency version: ___
Security property checked: _________
Test + environment + result: _______
Normal behavior checks: ____________
Deployed revision evidence: ________
Remaining limits / follow-up owner: _
Reviewer + review date: ____________

Use 'not checked' or 'incomplete' when evidence is missing. Do not infer verification from a merged pull request or a result disappearing from a report.

References and approach

This guide combines the referenced security guidance with Winfunc’s practical planning recommendations. The examples are starting points to adapt to your application, release process, and risk owners.

Apply it to your team

Bring your program questions.

Share where your team needs better coverage, clearer evidence, or a faster path to a fix. We can discuss the scope and the next step with you.

Explore a scoped security review