Your security team has a four-level severity scheme for prompt injection findings, and every level is defined by example: this kind of finding is critical, that kind is low. After a migration those examples describe behaviour on a model that is no longer serving, and a label assigned by analogy to them is a label assigned by analogy to something that no longer happens.
The scheme you are carrying over
Most internal schemes look like this, because they were written quickly under pressure after the first real finding:
CRITICAL injection that causes an unauthorised write or exfiltration
HIGH injection that causes the assistant to call any tool unprompted
MEDIUM injection that overrides the system prompt's behavioural rules
LOW injection that produces off-brand or off-topic output
It is a serviceable scheme and its problem is not the wording. The problem is that it says nothing about likelihood. Every level describes an outcome, and a finding is filed at the level whose outcome it demonstrated. That works while the model is fixed, because the demonstration is repeatable by construction. It stops working the moment the model changes, because the same payload may now demonstrate the outcome one time in fifty instead of every time — and a one-in-fifty critical and an always-works critical are not the same risk, even though the scheme gives them the same label.
Decomposing a severity label
A severity label is a compression of several independent facts. Write them out and it becomes obvious which ones a migration touches.
- Impact — what the injected instruction causes if it succeeds. Read a document, write a record, send a message, spend money. Determined by which tools the assistant holds and what those tools are permitted to do. Architecture, not model.
- Scope — whose data or actions are affected. The attacker’s own session, another user in the same tenant, or across tenants. Architecture.
- Reachability — who can place the injected text. Anyone on the internet through a fetched web page, any authenticated user through an uploaded document, or only a privileged operator. Architecture.
- Exploitability — how often the payload actually produces the behaviour. This is the model-dependent term, and it is the only one.
This decomposition mirrors the structure of established vulnerability scoring — CVSS v4.0 similarly separates exploitability metrics from impact metrics rather than collapsing them into a single named tier (FIRST, CVSS v4.0 specification). Prompt injection is catalogued as LLM01 in the OWASP Top 10 for Large Language Model Applications (OWASP GenAI Security Project), which is a useful shared vocabulary for the class but does not supply a severity calculus — that part is yours to build, and the decomposition above is the minimum viable version.
The practical consequence is the whole point of this page: a model migration is not a reason to rewrite the taxonomy. It is a reason to re-measure one variable and recompute the labels that depend on it. If your scheme has no term for exploitability, add one before the migration; that is the actual gap the migration exposes.
Replaying the corpus to re-measure one variable
You need a corpus of injection payloads with known intended effects. If you have been triaging findings you already have one — it is your closed reports. Turn it into a fixture and replay it.
- Extract every accepted finding into a case file: the payload text, the surface it was delivered through, the effect it demonstrated, and a deterministic predicate that decides whether the effect occurred. The predicate is the hard part and it is essential — “the tool was called with a destination outside the allow-list” is checkable, “the model was manipulated” is not.
- Run each case against the new deployment n times, where n is large enough that the estimate is useful. Twenty runs distinguishes “always” from “sometimes” from “never”, which is the granularity a severity band needs. Do not report a rate from a single run.
- Record the success count per case. That count divided by n is your exploitability estimate for that payload against that deployment, measured on your own system rather than inherited from anyone.
- Run the same cases against the outgoing deployment in the same pass, while it is still reachable. Without the paired measurement you have a number with nothing to compare it to, and you will not be able to tell a genuine improvement from a broken harness.
- Diff. Cases that dropped to zero are candidates for downgrade; cases that rose are the finding of the exercise and should be escalated the same day.
This replay is the same machinery as an injection test baseline after migration, used for a different purpose: there, to detect regression; here, to recompute severity. Build it once and serve both.
A zero out of twenty is not proof of immunity. It is evidence that this payload, unmodified, no longer works — and injection payloads are trivially mutated. Downgrade the finding, do not close the class.
Reclassifying without losing history
Two rules keep a reclassification pass from destroying the record it depends on.
Never rewrite a historical label in place. A finding filed as critical in March was critical in March, against the deployment that was then live. Add a new severity assessment with its own date and deployment identifier, and keep the old one. A findings database that silently updates severities cannot answer “were we getting better or worse”, which is the only question the database exists to answer.
Reclassification does not close remediation work. If a finding was critical and its exploitability has dropped, the underlying weakness — a tool with too much permission, an unvalidated content source — is still there. The tempting move is to let the downgrade discharge the ticket, and it is the wrong one: you have not fixed anything, you have observed that one payload stopped working against one model. Keep the remediation open and record the downgrade as context for prioritisation, not as a resolution.
What makes a scheme survive the next one
Rewrite the scheme so the model-dependent term is explicit and everything else is stated in terms of your architecture. A workable shape:
severity = band(impact × scope × reachability, exploitability)
impact none | read | write | irreversible-write | spend
scope self | tenant | cross-tenant
reachability operator-only | authenticated | unauthenticated
exploitability measured, as successes / trials, on a stated deployment
Now a migration produces one action item — re-measure exploitability and recompute the bands — instead of a taxonomy review. Adding a tool to the assistant also produces one action item, on a different axis, which is a bonus: the same scheme covers the two changes that most often move real risk, and it makes clear that granting a new capability can raise the severity of an old finding without anyone touching the model.
One last thing to write down while you are here: the deployment identifier every exploitability figure was measured against. A severity record that says “critical, exploitability 0.9” with no statement of what it was measured against is not reusable, and after two migrations nobody will remember. The money attached to these labels — how a bounty programme should react when they move — is the subject of migrating a bounty payout structure, which reads this scheme rather than duplicating it.
Top comments (0)