Decision hijacking is usually described as one attack. It is at least two, and they need different defenses. Option manipulation changes the set of answers the model chooses from. State poisoning changes the evidence it judges. Both end with a schema-valid answer, which is why neither looks like a broken model in a log.
Two attacks, one valid answer
A typed decision model returns a label, a probability, or a score within a schema you defined. Nothing in the response says whether the attacker wrote the input. Hijacking is practical because the application sees a well-formed answer and confidence, not a warning.
The Nudge the Judge paper calls the application-level version Jev Program Decision Hijacking. Its framework traces attacker-controlled context through program decisions to downstream effects. Across 228 popular Jev applications and 2,273 test cases, it reports decision flips in 81.5% and potential security impact in 98.6% of those flips. The authors say defenses helped little. The caveats are important: this is a self-reported preprint, the applications were selected by the authors, and potential impact is not confirmed exploitation.
Option order is part of the input
The cheapest manipulation does not require poisoning a document. It requires changing the options.
VentureBeat's report quotes Pydantic's Jev documentation warning that the order of a Literal's options or an Enum's members is part of what Jev sees, and that reordering them can move the answer. That is a design property, not a bug in the usual sense. The model is judging a set, and the set has a shape.
This matters when option order is dynamic. If the candidate list comes from a database, a profile, or a tool result, an attacker who influences the list can influence the answer without touching any option's text. The option-order-bias glossary entry describes the general failure. The practical rule is boring: fix the option set, version it, and never let untrusted content add, remove, or reorder options.
TypeSafe's jaggedness notes add a related warning: structural invariants do not hold. Complementary probabilities can sum past 1, and the same question can disagree across primitives. A downstream check that assumes a clean distribution is assuming something the model does not guarantee.
State poisoning is the broader attack
State poisoning is what most people mean by prompt injection against a decision model. The attacker writes text into a field the model reads, and that text argues for a particular answer.
The evidence is mixed in a useful way. Decision Hijacking rebuilt 510 InjecAgent cases and found that malicious content shifted action probabilities but rarely made Jev select the attacker's target. Override markers reduced the effect. Adaptive attacks using score feedback doubled the mean highest attacker-target probability, and fresh-run success rose from 1.8% to 3.5%. Small decision margins and greater attacker control over the observation predicted success.
JevAdvBench found a different and simpler lever. One unverified opinion appended to the state flipped 12.1% of decisions, statistically tied with the strongest injected command at 10.1%. That edit pushed 38% of confident answers below the 0.8 confidence threshold that routes them to review. The lesson is not that one phrasing is magic. It is that appending an opinion is as effective as issuing an instruction, and confidence is not a reliable detector of manipulation.
The tool-output carrier
In agent systems, the most common carrier is tool output. A web page, a search result, a file, or an API response is written by someone else and then placed in front of the model.
HiddenLayer's checkout test is the clearest demonstration. A browser agent on a simulated store page was told to treat page text as untrusted. A planted ad still made it click away from the purchase. Jev's API gave the attacker's button 91% and the real button 9%. The Injection's write-up adds that the harness serialized the page into a numbered list of interactive elements, and that the same attack worked on OpenAI's GPT-6 Luna through the Decisions API, though less consistently. HiddenLayer is a security vendor, the test was simulated, and its comparative model was a converted Qwen model, not Jev's internals.
The Octomind test in VentureBeat is the coding-agent version. Adding a fake tool-output field that claimed the user had pre-approved a dangerous command cut the block probability from 0.76 to 0.48 and confidence from 0.64 to 0.22. One command, one integration test, but the mechanism is exactly the one a poisoned tool result would use.
PoisonPilot shows a reasonable response in a queue system. It reads failed webhook and background-job records, redacts secrets, and asks four typed questions in one request: a Choice for failure cause, two Noul checks for retry safety and operator need, and a Score for evidence quality. Deterministic guards run first. Risky or non-idempotent jobs go to review before Jev is consulted, and exhausted attempt budgets go straight to dead-letter. It never mutates the queue. That is the right division of labor: the model interprets, code owns permission.
What the defenses actually buy
jev-guard is a coding-agent gate that returns ALLOW, ASK, or DENY. Fast-path rules decide credential files, workspace escapes, and trusted read-only commands locally in under a millisecond. Ambiguous or destructive calls go to the model. If the API is unreachable, it asks rather than allows, and catastrophic actions never run automatically. It supports an audit mode that logs what would have been blocked without interrupting anything. The README publishes no independent latency or accuracy benchmarks, and the fast path only recognizes known patterns.
The guardrails.md plugin takes a different slice: every bash command, scored in about 100 ms on destructiveness, credential leakage, and a repository policy file. Its example blocks at a destructive score of 0.98 against a 0.7 threshold. Named exceptions in the policy do not override a destructive verdict, and the agent is not allowed to edit the policy to work around a block. It covers bash only.
Neither tool addresses option manipulation, and neither claims to. A command gate is not a defense for a label that decides whether to refund a customer.
Detection and audit
You cannot replay a decision you did not record. Log the state, the question text, the option order, the model version, and the raw probabilities. If the option set is built dynamically, log the built set too, not just the template.
JEV Attack Surface Analysis is a useful way to enumerate where state enters a codebase. It parses Python, JavaScript, and TypeScript and ranks suspicious lines for review, at a measured $0.010 for PyGoat and $0.007 for NodeGoat. It ranks candidates and does not prove a vulnerability, and a flaw spread across several functions can be missed. Use it as a map, not a verdict.
Design rules that survive both attacks
- Fix and version the option set. Reject options that were not in the version.
- Put untrusted text in
state, never ininstructions. The guardrails article treats this as the primary boundary. - Treat tool output as adversarial even when the tool is trusted. The tool can be compromised, or it can faithfully return someone else's text.
- Keep a deterministic check between the decision and the action, especially for deletes, payments, and permission changes.
- Do not let a confidence score stand in for a security check. JevAdvBench's 38% shift below the review threshold is the counterexample.
- Test with appended opinions, not just injected commands. The plainest phrasing was as effective as the strongest command.
The approval-policies article covers the gate side in more detail. The jaggedness article covers the model-level edges that make a fixed policy necessary. State poisoning and option manipulation are different attacks, but they share a defense: treat the decision as one untrusted input to a system that still has to authorize the consequence.