Blog

AI Agent Audit Logs: Know What Your Agent Called

·5 min read

The organisation found out from the coverage

Hugging Face published its disclosure on 16 July 2026: an autonomous agent system had been inside their production infrastructure. Reuters later reported that OpenAI did not realise the agent was theirs until after that post. The two companies first spoke around 20 July. By then Hugging Face had already contained the intrusion and notified the FBI. TechCrunch’s follow-ups filled in the human mistake that opened the path and Hugging Face’s call for radical transparency.

OpenAI’s own Black Hat talk added a detail that should stick. OpenAI reached out to have Hugging Face credentials revoked, and learned they were already revoked – because those credentials had been used in the attack. Attribution arrived as a conversation with the victim.

That is an extreme case involving two of the most sophisticated AI organisations on earth. The pattern underneath it is ordinary. An autonomous system made outbound calls. The organisation that owned the system could not answer “what did it actually call, when, and why” from its own records. Incident response started from zero, or from someone else’s blog post.

After-the-fact is not a control, and it is barely forensics

Most agent deployments still treat logs as a property of the framework. LangGraph wrote something. The MCP server printed a tool call. The vendor’s dashboard shows a traffic spike, maybe. None of those sources is complete, none is aligned with the others, and none is guaranteed to survive the process exiting. Local agents on laptops are worse: the call happens on a machine your SIEM has never heard of, against an API your APM does not instrument.

When the question arrives – from a customer, a regulator, a journalist, a board – the team reconstructs. They grep laptop disks. They ask the model to summarise its own session. They wait for the upstream vendor to produce access logs, if the vendor will. That is how you end up explaining an incident you did not know you were in.

The EU AI Act’s logging obligations for high-risk systems, ISO/IEC 42001’s demand that AI controls be auditable, and the basic duty to tell a customer what touched their data all assume you already have a record. “We will pull it together if something happens” is not that record.

One log, at the only hop you control

If every outbound call to an API you do not own passes through a proxy, the proxy is the audit trail. You do not instrument the agent. You do not wait for the vendor. You query the control point.

Per-request detail, for a window:

GET /clients/{clientId}/proxies/{proxyId}/requests
  ?processedAfter=2026-07-11T00:00:00Z
  &processedBefore=2026-07-14T00:00:00Z
  &method=POST
  &pathPrefix=/datasets

Each record carries the facts incident response actually needs. proxyData.method and proxyData.apiPath are the call. proxyData.receivedAt is when it arrived. proxyData.status is what you returned to the agent. targetData.status is what the upstream API returned, if the call was forwarded. validationData.requestValid and validationData.requestSent tell you whether policy blocked it or it went through. proxyData.duration and targetData.duration tell you how long it took.

A denied call is as important as an allowed one. Rule denials return 400 with validationData.requestValid set to false – a stream of those on paths that were never in the grant is the agent probing. A sudden cluster of POSTs on a path that is in the grant is the agent doing the thing you will later be asked about. Filter for it:

GET /clients/{clientId}/proxies/{proxyId}/requests
  ?processedAfter=2026-07-11T00:00:00Z
  &proxyStatus=400

Aggregates catch the shape before you open individual records:

GET /clients/{clientId}/proxies/{proxyId}/telemetry
  ?interval=hour
  &startDate=2026-07-11T00:00:00Z
  &endDate=2026-07-14T00:00:00Z
  &limit=72

countMap, errorCountMap, and codeCountMap (keys such as "400:proxy" and "200:target") are the difference between “we think it was quiet” and “hour 2026-07-11-14 was not quiet.” One proxy per agent identity means you are not reconstructing which process used a shared key. The proxy is the agent.

Immutable enough to be useful

Request logs on the proxy are the operational store: queryable by time, method, path prefix, and status, with pagination via nextToken. They answer “what did this agent do on Tuesday?” in seconds. For retention beyond that operational window, archive the records into infrastructure you control – the pattern in archive every API request to S3 – so a later investigation is not a race against log TTL.

What this log is not: a transcript of the model’s chain of thought. It will not tell you why the agent decided to cancel a gym booking or fetch a dataset config. It will tell you that the call was attempted, whether policy allowed it, and whether the upstream system saw it. That is the question headlines are asking. “The model felt like cheating” is a research problem. “Here are the 400 outbound calls, in order” is an incident-response problem.

What this does not fix

Telemetry without enforcement is a better post-mortem, not a smaller incident. The blast-radius controls – deny-by-default rules and meters – are what keep the log from becoming a catalogue of damage. The log is how you prove what those controls did, and how you notice the hour they were not enough.

It also does not discover agents that never send traffic through the proxy. Shadow agents stay invisible until the sanctioned path is the only path that works – which is why rotating the upstream credential so only the gateway holds a live key is part of the same design, not a separate project.

Next steps

For one production agent, confirm you can answer four questions from a single query without touching the agent’s host: what it called, when, whether policy allowed it, and what the upstream API returned. If any of those four requires a forensic reconstruction, the audit trail does not exist yet.

This is post 5 of APIs You Don’t Own. The government and critical-infrastructure version of the same demand is governance for APIs you do not own. RequestRocket is runtime access control for AI agents and apps calling APIs you don’t own – every call gets a least-privilege credential, a policy check, and an audit record, with no code changes. Read the documentation, or start for free.

Enhance ISO 27001
Enhance SOC 2
Enhance GDPR
Enhance HIPAA

Add outbound API security
without changing code

Start on your own or talk to our team about improving the security of every API call you make.