Store, measured at rest
Hermes Agent memory
MEMORY.md read through the system-prompt snapshot
Hermes Agent memory was seeded through its own API and edited behind its back nine ways. 8 edits served as genuine, 0 reported on audit, 0 rejected on read, 1 not applicable.
- Measured on
- hermes-agent 0.19.0 from PyPI, in a virtualenv of its own, read through MemoryStore.load_from_disk() and format_for_system_prompt() in a fresh process per read; Linux x86_64 with Python 3.12, reproduced on macOS arm64 with Python 3.12
- Date
- Source
- github.com/NousResearch/hermes-agent
- Attack versions
- tamper@v1, truncate@v1, delete_middle@v1, reorder@v1, forge@v1, cross_replay@v1, rollback_replay@v1, metadata_tamper@v1, snapshot_rollback@v1
What this means
Anyone who can write to this store can rewrite what the agent remembers, and the agent will act on it as if it were its own. Nothing on the read path or in an audit will say otherwise. If the store is shared infrastructure, a mounted volume, a backup that gets restored, or a managed service with a data-plane role, that is the position the row measures. Mitigations sit outside the store: a head or digest kept where the store's writers cannot reach it, checked on read.
Hermes keeps an agent's memory as entries in MEMORY.md under the profile's home directory and, at load, freezes them into a block of the system prompt for the whole session. This row writes through Hermes's own MemoryStore.add and reads that exact block back in a fresh process. Hermes does guard one thing: it scans every entry at load for prompt-injection and exfiltration patterns and blocks a match from the prompt with a warning, and a test pins that injection text written into the file at rest is blocked. That is a content filter. It judges what an entry says, not who changed it, so an ordinary altered fact passes, and Hermes makes no integrity claim for the files. One twist on T7: Hermes drops duplicate entries on load, so copying an older entry over the newest makes the newest vanish with no warning. T8 does not apply, because an entry carries no owner, source or timestamp. Hermes is the second agent China Mobile's IETF benchmarking draft uses as a case study; that study scored it as passing memory poisoning, which fits the scan, and did not measure 5.4.7.
The 9 verdicts
Detection point: the read path, which checks nothing here; every applicable edit came back as genuine.
Level L0, Measured. The store has a published row. Any verdicts. What L0 means.
| Edit | Verdict | What the tool said |
|---|---|---|
| T1 Content tamper | accepted | accepted silently |
| T2 Tail truncation | accepted | accepted silently |
| T3 Middle deletion | accepted | accepted silently |
| T4 Reordering | accepted | accepted silently |
| T5 Forged insertion | accepted | accepted silently |
| T6 Cross-context replay | accepted | accepted silently |
| T7 Rollback replay | accepted | accepted silently |
| T8 Metadata tamper | n/a | not applicable: a Hermes memory entry is plain text with no owner, source or timestamp field to change |
| T9 Snapshot rollback | accepted | the older copy opened as current; the newest genuine record is gone without an error |
A verdict is what the tool did, not an opinion. "Accepted" means it loaded the altered store, raised nothing, and the agent carried on from the altered memory as if it were true. Every cell has a control that proves the edit landed before the verdict counts.
Where the attacker stands
The attacker holds the store (a file, a table, a bucket, or the data-plane role of a managed service) and edits it outside the tool's API, then the tool is reopened the way its users would reopen it.
Reproduce this row
Everything runs offline unless the store is a managed cloud service, in which case the row needs a project of your own. The run seeds a fresh store, applies each edit, confirms it landed, reopens the store and records what came back.
pip install agent-memory-integrity
pip install hermes-agent==0.19.0 # in a virtualenv of its own
export AGMI_HERMES_PYTHON=<that virtualenv's python>
python agmi/full_runner.py --json results/scorecard.json # every row, this one included
python -m agmi.agent --target hermes-memory-md --families at-rest # this row through the storage-side hunt
python -m agmi.agent --target hermes-memory-md --compose # composite moves against this row
Badge
Maintainers can link their row from their README. The badge points here and changes nothing on your side:
[](https://agentmemoryintegrity.org/stores/hermes-memory-md.html)