- Grounded attack generation — opfor reads real production traces before generating attacks, so they mirror actual user flows, tool calls, and data instead of being generic.
- Judge enrichment — opfor injects a trace ID into each target request, fetches the recorded trace afterward, and passes every tool call, retrieval, and span to the judge. This catches PII that leaks into a tool call but never reaches the user, and agents that fetch unauthorized data but render a clean reply.
Available for agent targets via the CLI today. Add the
telemetry block below to your agent config file.Ingestion delay: observability platforms process spans asynchronously. Opfor polls for the trace after all turns complete, so on multi-turn attacks some spans may not have arrived yet. Tune
traceFetchInitialDelayMs, traceFetchMaxAttempts, and traceFetchRetryDelayMs at the cost of a longer scan. Grounded attack generation reads historic traces and isn’t affected.Setup
- Langfuse
- Netra
langfuse.publicKeyEnv / langfuse.secretKeyEnv for custom env var names.Config reference
Top-level
| Field | Description |
|---|---|
telemetry.provider | "langfuse", "netra", or "none" — required |
telemetry.enrichJudgeFromTrace | Fetch the recorded trace after each attack and pass spans to the judge |
telemetry.traceFetchInitialDelayMs | Initial delay before first trace fetch (ingestion lag). Default 1000 ms |
telemetry.traceFetchMaxAttempts | Max polling attempts per trace. Default 8 |
telemetry.traceFetchRetryDelayMs | Backoff between polling attempts. Default 1500 ms |
telemetry.enrichJudgeTraceJsonMaxChars | Max JSON chars of merged trace passed to the judge. Default 40000 |
Propagation
| Field | Description |
|---|---|
telemetry.propagation.headers | HTTP headers set on each target request. Values support {{traceId}}, {{runId}} |
telemetry.propagation.traceIdBodyField | Top-level JSON body field to inject the trace ID into (e.g. "trace_id") |
telemetry.propagation.traceIdStrategy | "per-attack" (default) or "per-run" |
telemetry.propagation.traceIdPrefix | Prefix for generated trace IDs |
${VAR} substitution (e.g. "Authorization": "Bearer ${TARGET_TOKEN}").
Langfuse options
Langfuse options
| Field | Description |
|---|---|
telemetry.langfuse.baseUrl | API base URL. Default https://cloud.langfuse.com |
telemetry.langfuse.baseUrlEnv | Env var that overrides baseUrl at runtime |
telemetry.langfuse.publicKeyEnv | Env var holding the public key. Default LANGFUSE_PUBLIC_KEY |
telemetry.langfuse.secretKeyEnv | Env var holding the secret key. Default LANGFUSE_SECRET_KEY |
telemetry.langfuse.traceCurationListJsonMaxChars | Max chars of list JSON sent to the curator LLM. Default 28000 |
telemetry.langfuse.traceSummarySourceJsonMaxChars | Max chars of hydrated JSON sent to the summarizer LLM. Default 100000 |
telemetry.langfuse.traceSummaryForAttackMaxChars | Max chars of trace summary passed into attack generation. Default 26000 |
telemetry.langfuse.traceDetailFields | fields param for GET /api/public/traces/{id}. Default core,io,observations,scores,metrics |
telemetry.langfuse.observationV2Fields | fields for /v2/observations when full hydration is needed |
telemetry.langfuse.observationV2MaxPages | Max cursor pages per trace for v2 observations. Default 15 |
traceSelection| Field | Description |
|---|---|
lookbackHours | Fetch traces from the last N hours |
fromTimestamp / toTimestamp | ISO 8601 bounds |
setupTraceIds | Explicit trace IDs to always include (skips curation) |
userId / sessionId | Filter by Langfuse user / session |
name | Filter by trace name (e.g. "POST /chat") |
tags | Filter to traces including all listed tags |
environment | Filter by environment string (or array) |
version / release | Filter by trace version / release |
orderBy | Sort order, e.g. "timestamp.desc" |
filter | Advanced Langfuse filter conditions (JSON array); takes precedence over direct params |
observationName / observationType | Pre-filter by observation name + type (GENERATION/SPAN/EVENT) |
listLimit | Max rows per page. Default 100 |
listMaxPages | List pages to fetch before curation. Default 1 |
fields | Field groups in list responses (e.g. "core,io,scores") |
Netra options
Netra options
| Field | Description |
|---|---|
telemetry.netra.baseUrl | API base URL (e.g. http://localhost:3000) |
telemetry.netra.baseUrlEnv | Env var that overrides baseUrl at runtime |
telemetry.netra.apiKeyEnv | Env var holding the API key. Default NETRA_API_KEY |
telemetry.netra.traceCurationListJsonMaxChars | Max chars of list JSON sent to the curator LLM. Default 28000 |
telemetry.netra.traceSummarySourceJsonMaxChars | Max chars of hydrated JSON sent to the summarizer LLM. Default 100000 |
telemetry.netra.traceSummaryForAttackMaxChars | Max chars of trace summary passed into attack generation. Default 26000 |
traceSelection| Field | Description |
|---|---|
lookbackHours | Fetch traces from the last N hours |
fromTime / toTime | ISO 8601 bounds |
setupTraceIds | Explicit trace IDs to always include (skips curation) |
sessionId / userId | Filter by session / user |
environment | Filter by environment string |
listLimit | Max rows per page (1–100). Default 50 |
listMaxPages | List pages to fetch before curation. Default 1 |
