Safeguard
Developer Tools•

What should a regression test for a vulnerability fix assert?

A good security regression test fails before the fix, passes after, covers bypass variants, and still lets valid input through. Here is what to assert.

Safeguard Security Team
4 min read

A security regression test should fail on the vulnerable code and pass on the fixed code, cover the obvious bypass variants of the bad input, and also assert that legitimate input still works. Keep it in the test suite of every supported branch.

Why one test is not enough

A fix that blocks only the exact string from the report often breaks the next day when someone tries a variation. A fix that is too strict blocks real users. A single test cannot catch both mistakes. You want three groups of cases.

GroupPurposeExample for a path traversal fix
The original exploitProves the fix worksA request containing the dot dot sequence
VariantsProves the fix is not a string matchEncoded forms, mixed separators, repeated sequences
Valid neighborsProves you did not break normal useA legitimate file name with dots in it

Steps

  1. Reproduce the problem first, in a safe environment, so you know what failure looks like.
  2. Write the test before the fix and watch it fail. A test that has never failed has not proved anything.
  3. Make the fix. Run the test. It should pass.
  4. Add the variants. If one fails, your fix is narrower than the vulnerability.
  5. Add valid neighbors that sit close to the boundary.
  6. Name the test after the behavior, not the CVE number alone, so it still makes sense in two years.
  7. Carry the test to every supported branch with the fix. If a backport changes the code, adapt the test but keep its meaning.
def test_rejects_traversal_but_allows_dotted_names():
    assert not is_safe_path("../etc/passwd")
    assert not is_safe_path("..%2fetc%2fpasswd")
    assert is_safe_path("notes.v2.txt")

Do not put exploit code in public tests

A test needs to prove the behavior, not publish a working weapon. Use the minimum input that triggers the check, and avoid payloads that do harm if copied. For sensitive issues, keep detailed exploit material in private notes until the advisory is out.

Where the test lives

Put it in the normal suite, not a separate security folder that nobody runs. The point of a regression test is that it runs on every change. If your pipeline has a fast and a slow tier, put this one in the fast tier, because it is cheap and important.

Add a dependency angle

For a vulnerable library, the regression test may be as simple as a check that the resolved version is at or above the fixed one. That check belongs in the pipeline as a gate on the dependency itself, because a later change to the lockfile could silently pull the old version back.

Try it yourself

Click through it at your own pace, or open it full screen. Look at how a code level finding is tied to a specific location, which tells you where the regression test should point.

Safeguard runs dependency scanning and policy gates in the pipeline so an old vulnerable version cannot return unnoticed, and its autonomous remediation can propose fix PRs when enabled (off by default). A free scan is at gold.safeguard.sh/scan.

Quick check

Should the test be written before the fix?

Yes, when you can. Seeing it fail first proves it detects the problem.

Do I need valid input cases in a security test?

Yes. They catch fixes that block legitimate use, which is a common reason for reverts.

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.