ANP has strong identity and encryption foundations — DID:WBA authentication and HPKE-based end-to-end encryption are well implemented. While reviewing the Python SDK, we identified four areas where the SDK could be hardened further.
This report is about security hardening / defense-in-depth, not an exploit report. The goal is to make it easier for applications built on top of the SDK to enforce authorization, observe security events, revoke credentials, and handle replay protection more robustly.
1. No consent / approval hook before operations execute
After DID authentication succeeds, operations execute immediately, with no interception point for the application to approve or deny the specific operation.
Examples:
fastanp/middleware.py (auth_middleware): once authenticate_request() succeeds, the middleware immediately calls call_next(request), with no hook for the application to inspect the operation and decide whether to allow it.
anp_crawler/anp_client.py (ANPClient.fetch_url): auth headers are attached and the request is sent in one step, with no approval gate between authentication and execution.
- OpenANP interface dispatch: when a remote agent calls an
@interface method, the framework dispatches directly to the handler after DID verification, with no before_execute / consent_required-style hook.
The gap is that authentication is not the same as per-operation authorization. A DID-verified agent can invoke any exposed interface unless the application adds its own ad hoc checks.
Suggestion:
Add an optional consent_callback / before_execute hook in the middleware and interface dispatcher, so applications can inspect operation metadata plus caller DID and return allow/deny before the handler runs.
2. No structured audit logging for security-relevant events
The SDK uses standard Python logging, but we did not find structured security event logging that applications can reliably consume for auditing or incident response.
Examples:
- Authentication success/failure is logged as plain text rather than as structured security events.
- Token issuance in
_create_access_token() has no structured audit record.
- Session creation/removal logs are human-readable but not queryable event objects.
- We did not find an
AuditLog, SecurityEvent, or similar abstraction, nor an application hook for receiving security-relevant events.
This makes it difficult to answer operational questions such as:
- Which agents authenticated in the last hour?
- Was a token used after a session was removed?
- Were repeated nonce failures observed for a given DID?
Suggestion:
Add a structured security event hook / emitter for events such as:
- auth attempt success/failure
- token issuance / expiry / rejection
- session creation / removal
- nonce rejection / replay detection
Applications could then forward these records to their own database, SIEM, or audit pipeline.
3. No active token revocation, only passive TTL expiry
Tokens appear to be created with a TTL and then accepted until expiration, with no server-side mechanism to revoke them early.
Examples:
_create_access_token() creates a JWT with an exp claim.
_handle_bearer_auth() checks expiration time, but not a revocation list.
did_wba_authenticator.py stores tokens client-side in memory; clear_token() / clear_all_tokens() clear the client cache only.
- Session cleanup in
fastanp/context.py removes session state, but does not appear to invalidate already-issued tokens.
As a result, if a token is leaked or a session is terminated, the token may remain usable until TTL expiry.
Suggestion:
Add optional server-side token revocation support, for example via:
- JTI-based revocation list
- revocation callback / token store interface
- revocation on session removal / logout
Even an in-memory revocation backend would improve the default security posture, while allowing deployers to swap in a persistent backend if needed.
4. Replay protection appears to be in-memory only
The SDK includes replay defenses, but the state appears to be maintained in memory only.
Examples:
- DID nonce validation keeps an in-memory nonce registry with TTL.
- HPKE/E2EE sequence tracking keeps per-session sequence state in memory.
- After process restart, previously seen nonce / sequence state may be lost.
This means replay protection is effective during normal process lifetime, but may not survive restart or cross-instance deployment unless the application adds its own persistent/shared state.
Suggestion:
Either add an optional persistent / pluggable backend for nonce and sequence tracking, or document clearly that replay protection is in-memory by default and that deployments requiring restart-resistant replay defense should provide external state.
Why this matters
These changes would make ANP easier to deploy in higher-trust or production settings:
- consent hooks for sensitive actions
- structured audit trails for incident response and compliance
- token revocation for post-session credential invalidation
- replay protection that survives restart or scales across instances
ANP has strong identity and encryption foundations — DID:WBA authentication and HPKE-based end-to-end encryption are well implemented. While reviewing the Python SDK, we identified four areas where the SDK could be hardened further.
This report is about security hardening / defense-in-depth, not an exploit report. The goal is to make it easier for applications built on top of the SDK to enforce authorization, observe security events, revoke credentials, and handle replay protection more robustly.
1. No consent / approval hook before operations execute
After DID authentication succeeds, operations execute immediately, with no interception point for the application to approve or deny the specific operation.
Examples:
fastanp/middleware.py(auth_middleware): onceauthenticate_request()succeeds, the middleware immediately callscall_next(request), with no hook for the application to inspect the operation and decide whether to allow it.anp_crawler/anp_client.py(ANPClient.fetch_url): auth headers are attached and the request is sent in one step, with no approval gate between authentication and execution.@interfacemethod, the framework dispatches directly to the handler after DID verification, with nobefore_execute/consent_required-style hook.The gap is that authentication is not the same as per-operation authorization. A DID-verified agent can invoke any exposed interface unless the application adds its own ad hoc checks.
Suggestion:
Add an optional
consent_callback/before_executehook in the middleware and interface dispatcher, so applications can inspect operation metadata plus caller DID and return allow/deny before the handler runs.2. No structured audit logging for security-relevant events
The SDK uses standard Python
logging, but we did not find structured security event logging that applications can reliably consume for auditing or incident response.Examples:
_create_access_token()has no structured audit record.AuditLog,SecurityEvent, or similar abstraction, nor an application hook for receiving security-relevant events.This makes it difficult to answer operational questions such as:
Suggestion:
Add a structured security event hook / emitter for events such as:
Applications could then forward these records to their own database, SIEM, or audit pipeline.
3. No active token revocation, only passive TTL expiry
Tokens appear to be created with a TTL and then accepted until expiration, with no server-side mechanism to revoke them early.
Examples:
_create_access_token()creates a JWT with anexpclaim._handle_bearer_auth()checks expiration time, but not a revocation list.did_wba_authenticator.pystores tokens client-side in memory;clear_token()/clear_all_tokens()clear the client cache only.fastanp/context.pyremoves session state, but does not appear to invalidate already-issued tokens.As a result, if a token is leaked or a session is terminated, the token may remain usable until TTL expiry.
Suggestion:
Add optional server-side token revocation support, for example via:
Even an in-memory revocation backend would improve the default security posture, while allowing deployers to swap in a persistent backend if needed.
4. Replay protection appears to be in-memory only
The SDK includes replay defenses, but the state appears to be maintained in memory only.
Examples:
This means replay protection is effective during normal process lifetime, but may not survive restart or cross-instance deployment unless the application adds its own persistent/shared state.
Suggestion:
Either add an optional persistent / pluggable backend for nonce and sequence tracking, or document clearly that replay protection is in-memory by default and that deployments requiring restart-resistant replay defense should provide external state.
Why this matters
These changes would make ANP easier to deploy in higher-trust or production settings: