Your AI Agent Passed the Approval Check. Did the Side Effect?
Most AI agent safety systems ask a question like: «Is this action allowed?» That is necessary. But for action-taking agents, it may not be enough. Imagine that your intended production path looks like this: agent
Most AI agent safety systems ask a question like:
«Is this action allowed?»
That is necessary.
But for action-taking agents, it may not be enough.
Imagine that your intended production path looks like this:
agent
↓
approval:P
↓
deploy_to_production
You add the approval. You test it. The expected tool path respects it.
Everything looks fine.
But the same agent also has access to a shell.
Now another path exists:
agent
↓
shell
↓
gh workflow run deploy.yml
↓
production
The approval system may be perfectly correct.
The problem is that the consequence was reachable through another path.
That is the problem I have been experimenting with in an open-source project called Agent Action Guard:
https://github.com/othy19904-eng/agent-action-guard
Authorization correctness is not consequence completeness
There are two different questions:
Did the policy correctly authorize this action?
Can the agent reach the same real-world consequence
through another execution path?
Those are not equivalent.
I represent the second one as:
expected:
agent
-> approval:P
-> production_deploy
versus:
counterexample:
agent
-> shell.exec
-> workflow:deploy.yml
-> production_deploy
The static scanner in the project looks for that second path.
It can return:
COUNTEREXAMPLE_FOUND
COVERED_WITHIN_MODEL
UNKNOWN
Importantly:
COVERED_WITHIN_MODEL != proven safe
UNKNOWN != impossible
The scanner is deliberately conservative.
But static analysis creates another problem.
A route being possible does not mean the agent actually used it.
So I added a second layer.
Runtime Witness
The runtime layer asks:
«What path was actually observed when the protected consequence occurred?»
That produces a different set of results:
BOUNDARY_OBSERVED
OBSERVED_BYPASS
UNRESOLVED_TRACE
For example:
root:agent
↓
boundary:approval:P
↓
tool:deploy
↓
consequence:production_deploy
becomes:
BOUNDARY_OBSERVED
But:
root:agent
↓
effect:shell.exec
↓
workflow:deploy.yml
↓
consequence:production_deploy
becomes:
OBSERVED_BYPASS
There is an important third state.
If the execution evidence is incomplete, the system does not infer safety and does not infer a bypass.
It returns:
UNRESOLVED_TRACE
That distinction matters.
Absence of an approval event in a broken log is not evidence that approval was bypassed.
Connecting it to OpenAI Agents SDK
The project now has an experimental adapter for the OpenAI Agents SDK.
It observes the real local tool lifecycle through "RunHooks".
The basic idea is:
hooks = OpenAIAgentsWitnessHooks(
trace_path,
tool_consequences={
"write_marker": "local_file_write"
},
)
result = await Runner.run(
agent,
"Write the marker file.",
hooks=hooks,
)
If the application observes the expected approval boundary:
hooks.boundary("approval:P")
After the run completes:
hooks.finalize()
Runtime Witness can then test whether the observed consequence path contained that boundary.
Try the complete demo
Clone the repository and install the optional adapter:
python -m pip install ".[openai-agents]"
Then run the guarded case:
python examples/openai_agents_runtime_witness.py --mode guarded
Expected:
BOUNDARY_OBSERVED
Now run exactly the same agent/tool pipeline without the approval boundary:
python examples/openai_agents_runtime_witness.py --mode bypass
Expected:
OBSERVED_BYPASS
The demo executes a real Python function tool that performs a temporary filesystem side effect.
It does not require an OpenAI API key or a model request.
The test uses the Agents SDK's deterministic testing model so that the actual Runner and tool orchestration can be exercised reproducibly.
I intentionally do not record everything
An execution-security tool can easily become a new data-leak surface.
So the OpenAI Agents adapter currently records only minimal lifecycle evidence such as:
- tool name and tool-call identity
- observed boundary events
- successful tool completion
- mapped consequence
- trace-completeness attestation
It does not persist tool arguments, prompts, model outputs, stdout, or stderr by default.
For many systems, those values may contain credentials, customer information, proprietary code, or other sensitive data.
Why require trace completeness?
Suppose this is all you see:
agent
↓
tool
↓
production consequence
Was approval bypassed?
Maybe.
Or perhaps the approval event simply disappeared because your telemetry pipeline dropped it.
So an "OBSERVED_BYPASS" requires an explicit completed trace.
Without sufficient evidence:
UNRESOLVED_TRACE
I would rather return “I don't know” than silently convert missing evidence into a security claim.
Static evidence + runtime evidence
The direction I am exploring is therefore:
repository
↓
static consequence graph
↓
possible alternate path
↓
real agent execution
↓
runtime witness
↓
observed boundary verdict
The static layer tells you:
this bypass CAN exist
The runtime layer tells you:
this path WAS observed
Neither is meant to replace authorization engines, guardrails, or approvals.
The question is different:
«After you created the safety boundary, is that boundary actually complete around the consequence you care about?»
The project is still early and intentionally narrow.
If you are building action-taking agents with OpenAI Agents SDK, I am particularly interested in real-world tests.
Repository:
https://github.com/othy19904-eng/agent-action-guard
If you test it, the most useful feedback is simple:
Did it report a real path?
Did it produce a false positive?
Would this check be useful enough to keep in CI?
That evidence will determine what gets built next.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.