Developer Guides
·IdenticAPI

How to Log AI Security Events Without Storing Sensitive Prompts

Log AI security events without storing sensitive prompts — metadata-first logging, verdicts, request IDs, and privacy-safe audit trails.

Security logging for AI applications is essential for incident response, compliance audit, and tuning guardrail policies — but naive logging recreates the data-leakage paths you are defending. Storing full prompts, completions, and tool payloads in centralized log pipelines often violates privacy commitments, expands breach blast radius, and trains support staff on sensitive customer content they should never see.

This guide shows how to log AI security events with a metadata-first approach: verdicts, categories, correlation IDs, and latency — without retaining sensitive prompt text. Pair with IdenticAPI request_id fields returned from guard APIs. Review usage and billing fields to understand what IdenticAPI returns per call and what your application should persist locally.

Related: AI agent runtime monitoring, protect API keys in SaaS.

The logging paradox

You need enough detail to answer:

  • Did guards run on this request?
  • Why was a message blocked?
  • Is a tenant seeing elevated false positives?
  • Can we correlate a user report with guard decisions?

You must not persist:

  • Raw user messages with PII
  • Full LLM completions
  • API keys or tokens in any field
  • Complete RAG chunks or tool arguments

If logs contain the same secrets guards blocked, you have moved the problem downstream.

Metadata-first event schema

Design structured events with fixed fields:

FieldExamplePurpose
eventai_guard_inputEvent type for queries
timestampISO 8601Ordering
request_idreq_guard_abcIdenticAPI correlation
app_request_idreq_app_xyzYour HTTP request ID
tenant_idtenant_acmeMulti-tenant scope
user_idusr_123User scope (hashed if required)
routePOST /v1/chatSurface identification
guard_apiunified-guardWhich product was called
checks["prompt_injection","pii_secrets"]Checks requested
decisionblockAggregated outcome
verdictsper-check mapDrill-down without text
finding_categories["api_key"]Why — no substrings
riskhighAlert thresholds
usage_units2Cost attribution (usage docs)
processing_time_ms38SLO tracking
detector_version1.0.0Regression on upgrades
policy_idUUIDTenant policy version
fail_modeclosedOutage behavior audit

Example: input guard event

{
  "event": "ai_guard_input",
  "timestamp": "2026-08-23T10:15:00Z",
  "app_request_id": "req_app_xyz",
  "request_id": "req_guard_abc",
  "tenant_id": "tenant_acme",
  "user_id": "usr_123",
  "route": "POST /v1/chat",
  "checks": ["prompt_injection", "pii_secrets"],
  "decision": "block",
  "verdicts": {
    "prompt_injection": "allow",
    "pii_secrets": "block"
  },
  "finding_categories": ["api_key"],
  "risk": "high",
  "usage_units": 2,
  "processing_time_ms": 41,
  "detector_version": "1.0.0"
}

Note what is absent: no text, no redacted_text, no finding offsets that enable reconstruction.

What IdenticAPI returns vs what you store

IdenticAPI responses include fields documented in usage and API reference:

  • request_idstore (primary correlation key)
  • verdict / decisionstore
  • findings[].categorystore categories and reasons at summary level
  • findings[].start / endavoid in production logs (enables substring recovery)
  • redacted_textdo not log; use transiently in memory for prompt substitution
  • usage_unitsstore for billing reconciliation
  • processing_time_msstore for latency dashboards

Treat API responses as ephemeral in the request handler. Persist only the metadata subset your security and ops teams need.

Correlation ID chain

Link events across a single user turn:

app_request_id
  → guard_input.request_id
  → llm_provider_request_id (if logged)
  → guard_output.request_id
  → render_event_id

For agents, extend with tool_execution_id and agent_action_guard.request_id.

During incidents, support asks: "What happened to message X?" You answer with IDs and decisions — not by searching log bodies for message content.

Logging per pipeline stage

StageEvent nameMinimum fields
Input guardai_guard_inputdecision, categories, request_id
LLM callllm_inferencemodel_id, token counts (not text), latency
Output guardai_guard_outputdecision, categories, request_id
Agent actionai_guard_agent_actiontool_name, action, decision, matched_rule
Policy bypassai_guard_bypassreason (outage, internal admin)
Review queueai_guard_review_enqueuedqueue_id, request_id

Emit ai_guard_bypass whenever fail-open paths activate — silent bypasses undermine audit.

Safe handling of finding reasons

IdenticAPI reasons strings describe why a check fired. They are safer than raw input but may still echo short sensitive fragments in edge cases.

Production practice:

  • Log finding_categories array reliably
  • Log generic reason_code if you map reasons internally
  • Restrict full reasons text to security-team-only sinks with short retention
  • Never forward reasons to client-visible error JSON

Client response on block:

{
  "error": "request_blocked",
  "message": "We could not process this message. Please rephrase.",
  "request_id": "req_guard_abc"
}

Debug mode vs production mode

Engineering teams need payload visibility during development. Separate environments:

EnvironmentPrompt logging
Local devOptional full text in console (synthetic data only)
StagingRedacted samples with access control
ProductionMetadata only

For production debugging of a specific incident:

  1. Use time-bounded secure replay buffers (encrypted, TTL < 24h, break-glass access)
  2. Require ticket approval for buffer reads
  3. Never enable buffer globally

Third-party observability vendors

Shipping logs to Datadog, Splunk, or CloudWatch exports data to another processor. Before forwarding:

  • Strip text fields at the emitter
  • Scan remaining JSON with PII & Secrets Detection if logs may contain accidental paste
  • Contractually limit vendor retention for security event streams
  • Disable full-message tracing on APM tools attached to LLM routes

Metrics derived from metadata

Build dashboards without prompt content:

MetricSource fieldUse
Block rate by tenantdecision, tenant_idAbuse detection
Category heatmapfinding_categoriesRule tuning
Guard latency p95processing_time_msSLO
Usage units per routeusage_units, routeCost (usage docs)
Fail-open countai_guard_bypassReliability
Review queue depthai_guard_review_enqueuedStaffing

Alert on spikes in api_key or private_key categories per tenant — may indicate credential paste attacks.

Retention policy

Data classSuggested retention
Guard metadata events90–365 days per compliance needs
Full debug buffersHours to 1 day
Review queue payloadsUntil resolved + short archive
Aggregated metrics13+ months

Document retention in your privacy policy. Metadata logs with user_id may still be personal data under GDPR — lawful basis and deletion workflows apply.

Compliance-oriented audit trail

For SOC 2 or enterprise customers, auditors ask whether controls operated — not to read chat content. Your trail should prove:

  1. Input guard ran before provider calls (ai_guard_input exists)
  2. Block decisions were enforced (no llm_inference after block)
  3. Output guard ran before delivery
  4. Policy version (policy_id) at time of decision

Export samples as anonymized event JSON, not conversation transcripts.

Implementation checklist

  • Structured JSON logs, not printf prose
  • request_id from every IdenticAPI call stored
  • No text, redacted_text, or finding offsets in production sinks
  • Client errors include request_id only
  • Fail-open events explicitly logged
  • Dashboards on metadata metrics
  • Retention and access controls documented
  • Third-party log forwarders reviewed for PII

Testing logging in CI

Assert log emitters in unit tests:

it("logs metadata without prompt text", () => {
  const spy = jest.spyOn(logger, "info");
  await handleChat({ message: "secret=api_key=sk_test_xxx" });
  const payload = JSON.parse(spy.mock.calls[0][0]);
  expect(payload).not.toHaveProperty("text");
  expect(payload.finding_categories).toContain("api_key");
  expect(payload.request_id).toMatch(/^req_/);
});

Summary

Log AI security events with metadata-first structured events: request_id, decision, finding_categories, tenant and route context, usage_units, and latency — not full prompts or completions. Correlate stages with app_request_id, restrict debug capture to break-glass buffers, and align persisted fields with IdenticAPI usage documentation. Metadata logging supports incident response without turning your log stack into a second data breach.

Review IdenticAPI usage and logging · Unified Guard

Frequently asked questions

What should AI security logs include?

Metadata: event type, timestamp, request_id, app_request_id, tenant_id, route, checks requested, decision, finding categories, risk, usage_units, processing_time_ms, and detector_version. Omit full prompts, completions, redacted_text, and finding character offsets.

Should I log IdenticAPI redacted_text?

No in production centralized logs. Use redacted_text transiently in memory to substitute provider payloads. Persisting redacted text can still hold recoverable PII and expands breach scope.

How do I correlate guard events across a chat turn?

Chain app_request_id to guard input request_id, optional LLM provider request ID, guard output request_id, and render events. For agents, add tool_execution_id and agent_action guard request_id.

What IdenticAPI response fields are safe to store long term?

Store request_id, decision or verdict, finding categories, risk, usage_units, processing_time_ms, and detector_version per IdenticAPI usage documentation. Avoid logging full API responses that include text bodies or offset metadata.

What should customers see when a request is blocked?

A static safe message plus request_id for support correlation — not finding reasons that might echo sensitive fragments and not the blocked model or user text.

Related reading