Inspiration
Robot forensics is fundamentally different from IT forensics. A cyber attack on a ROS2 robot produces physical consequences . Real life example: flooded command topic can send a robot into an obstacle, a replaced camera feed can make it navigate at outdoor speed indoors. Yet existing LLM-based DFIR tools either give the agent unrestricted shell access (spoliation risk) or rely on a prompt instruction saying 'don't modify evidence' which an agent can ignore, misinterpret or hallucinate compliance with.
We wanted to build a robot IR agent where evidence integrity is architecturally enforced, not instructed and where the agent's accuracy claims are measurable.
What it does
An autonomous DFIR agent that triages compromised ROS2 robots on SIFT Workstation — no human in the loop.
Given a ROS2 attack bag and a baseline, it:
- Detects command-topic flooding (19.86 Hz normal → 165.22 Hz attack, 8.3× spike)
- Detects camera feed replacement (indoor→outdoor scene shift,9.3-second gap physically impossible from a real camera pan)
- Cross-verifies cyber and physical attack layers via a multi-agent system, surfacing a compound Safety:HIGH hazard neither agent saw alone
- Traces every conclusion back to the exact tool call that produced it(structured audit trail with sequence numbers and timestamps)
- Never modifies original evidence — architecturally enforced, sha256-verified
- Measures its own hallucination rate deterministically
How we built it
Each architectural upgrade was forced by a measured failure
| Stage | Change | Why (measured failure) |
|---|---|---|
| V0 | Single agent + shell access | Starting point |
| V1 | Custom read-only MCP server | Agent started querying sqlite3 directly → spoliation risk, no audit trail |
| V2 | Real benchmark + 2-tier verifier | Self-made data = circular logic. Verifier had population error → hallucination rate fixed |
| V3 (MAS) | Cyber + physical + synthesizer agents | E2 camera data arrived → single-context cross-layer verification impossible |
Architecture:
- A custom MCP server exposes 8 read-only forensic functions
(
extract_command_timeline,diff_against_baseline,check_perception_consistency, etc.) with no write, delete, or shell access — architectural enforcement, not prompt restriction. - SHA-256 hashes at intake and post-analysis confirm
modified: false(spoliation test passed). - A two-tier hallucination verifier: Tier 1 recomputes evidence deterministically and validates
citation chains against
audit.jsonl; Tier 2 uses an independent-vendor LLM judge (OpenAI gpt-4o-mini) for inferred claims only, reported separately and never folded into the headline rate. - Data: public benchmark — "Simulated attacks Rosbags against mobile robot in ROS 2" (Zenodo 17649537, EU TESCAC, 2025). Not our own data.
Challenges we ran into
The verifier bug. When 0.667 appeared, the temptation was to loosen the verifier to make the number look better. We did the opposite — tightened the claim taxonomy, separated the populations, and let the corrected rate speak for itself (0.0). Documenting this failure is the honest version of "what we learned."
MAS audit gap. The physical agent's tool calls ran in a separate session and were not
written to the shared audit.jsonl. The synthesizer detected and flagged this gap
automatically in the final report. We documented it as a known limitation rather than
hiding it — a complete chain-of-custody requires a shared audit log across all agents.
Physical layer signal. E1's attack floods cmd_vel with value=0 at 165 Hz — so
predicted_displacement ≈ actual_displacement ≈ 0, and motion consistency returns
consistent. This is not a tool failure; it reveals that this attack is physically covert
by design (rate anomaly only, no velocity hijack). The MAS physical agent reported this
correctly, and the synthesizer used it to sharpen the compound hazard assessment.
Accomplishments that we're proud of
The verifier caught its own bug. Our first verifier returned 0.667. We didn't loosen the rules to make the number look better — we dug in and found a population error: execution assurances were mixed into the hallucination denominator alongside attack claims. Fixing the measurement dropped the rate to 0.0. We're proud that we chose to fix the science rather than the score.
Self-correction that actually works and we can prove it. The agent corrected its own wrong assumption about the command topic. Not because we prompted it to "double-check." Because the MCP server returned TOPIC_NOT_FOUND — a hard external signal. The correction is recorded in audit.jsonl (seq 2: failed, seq 3: metadata lookup, seq 4: retry success). Verified from the trace, not from self-report.
A compound hazard no single agent could see. When the MAS synthesizer cross-verified the cyber agent (command flood) and physical agent (camera replacement), it found something neither saw alone: Safety:HIGH. E1 removes motor control reliability. E2 removes situational awareness. Together, the robot may navigate at outdoor speed indoors — endangering personnel. That insight only exists because the agents were separated and then reconciled.
What we learned
The biggest surprise: hallucination measurement itself can be wrong.
Our first verifier produced a hallucination rate of 0.667. Our manual analysis revealed the agent had not hallucinated — the verifier had a population error: it mixed attack findings and execution assurances (read-only architecture, integrity check) in the same denominator. These are architectural properties, not bag-evidence claims. Counting them violated FActScore's claim-scoping convention. Separating case_findings from execution_assurance dropped the rate dramatically.
Self-correction cannot be prompted — it must be triggered externally.
Research shows LLMs cannot reliably fix their own mistakes when simply told to "check your answer" (Huang et al., ICLR 2024; Kamoi et al., TACL 2024). What works instead: giving the model a concrete external error signal to react to.
That's exactly what happened here. Our agent assumed the robot's command topic would be /cmd_vel. The MCP server returned TOPIC_NOT_FOUND. The agent recognised its assumption was wrong, wrote CORRECTION:, called parse_bag_metadata to list the real topics, found /mobile_base_controller/cmd_vel, and retried successfully.
The agent didn't self-correct because we asked it to. It self-corrected because the tool gave it hard evidence that it was wrong. That's the difference between a prompt guardrail and an architectural one.
Two attacks together are worse than the sum of their parts.
Running the MAS synthesizer over both E1 (command flooding) and E2 (camera replacement)revealed a compound hazard neither agent saw alone: E1 removes motor control reliability, E2 removes situational awareness. Together, an autonomous robot may attempt outdoor-speed navigation indoors — Safety: HIGH. Single-agent analysis missed this entirely.
What's next for SIFT_ROS Agent
- Attack detection latency: quantify how many malicious commands execute before the agent detects the attack
- Physical watermarking: inject pseudorandom signals into motor commands to detect FDIA even when odometry shows zero displacement.
Built With
- claude
- openaiapi
- ros2
- rosbags
- sift
- ubuntu
Log in or sign up for Devpost to join the conversation.