Skip to main content

Agent-embedded security monitor. Instruments the four agent boundaries (model-client, framework tool-dispatch, MCP, effect) and reports findings to a control plane.

Project description

Nyx Agentic Detection & Response (ADR)

Part of the Nyx Security platform (root README) — the ADR capability: the in-process instrument SDK (nyx/) + the control plane / agentic SIEM (control-plane/). Its sibling is Agentic Security Posture at products/posture/. Integration flows one-way, posture → ADR.

An agent-embedded security monitor. Nyx instruments the boundaries of an agent process in-place and reports findings to a control plane. It runs inside the agent — no proxy, no sidecar required — and is designed to do no harm: a bug in instrumentation must never take down the host agent.

The four boundaries

Boundary What it wraps What you learn
model_client openai chat.completions, anthropic messages, litellm, bedrock (boto3 Converse/InvokeModel), vertex (Gemini) Intent: system prompt, messages, tool schemas offered, tool_calls chosen
tool_dispatch LangChain BaseTool.run/arun, LlamaIndex FunctionTool.call, CrewAI BaseTool.run, AutoGen FunctionTool.run Action: this agent, this run, this tool, these args
mcp client ClientSession.call_tool + server FastMCP.call_tool / low-level Server handlers + protocol metadata (transport/server) Action + protocol: tool, args, both sides of the call, and the assessment point for authz / confused-deputy
effect httpx, requests, aiohttp, subprocess.Popen, os.system Ground truth: what actually happened, even from raw code that bypassed every framework

The effect boundary is the backstop: without it, coverage is only as good as the framework-adapter list. With it, Nyx catches the agent writing and running raw code that bypasses every abstraction.

Status

Built and tested, default observe-only:

  • L1 capturemodel_client (OpenAI + Anthropic + litellm + Bedrock + Vertex), tool_dispatch (LangChain + LlamaIndex + CrewAI + AutoGen), mcp (client + server: FastMCP & low-level Server, + protocol metadata), effect (httpx/requests/aiohttp/subprocess/os.system)
  • L2 attribution — stack/line capture (gated) and identity/NHI capture (cred type, source, fingerprint — never the secret)
  • L3 correlationcontextvars span chain: effects nest under the tool span that triggered them; whole chain shares a trace_id
  • L4/L5 policy — decision evaluated on every call and recorded; shadow-mode rollup; enforcement gated behind mode="enforce"
  • Metadata-only by default (principle 6) — payloads (messages/tool args/response text) are hashed at ship time; metadata always sent. Detectors still see raw content in-process (principle 3: capture in-process, decide locally, ship metadata).
  • Coverage honesty (principle 7) — subprocess / os.system events carry an explicit coverage_gap (execution leaves the interpreter)
  • Framework mapping — findings carry version-stamped ATLAS / OWASP Agentic ids
  • Hardened L1 patching — uses wrapt when installed (descriptor/signature-safe, survives version drift), hardened functools+setattr fallback otherwise; backend-agnostic, idempotent, never crashes import. Guarded by a per-adapter conformance suite.
  • Self-observability (§9) — nyx.metrics(): events per boundary, coverage gaps, enforced vs. would-act, patch failures, reporter queue health
  • Co-located engine split (§5/§6.6) — optional UDSSink ships telemetry to a separate python -m nyx.engine process over a Unix socket (fail-open); the blocking decision stays local in-process
  • ✅ Non-blocking reporter (drop-on-overflow), zero hard dependencies (wrapt optional), self-traffic suppression
  • ✅ Overhead measured, not asserted: ~14µs/call wrapper overhead worst-case (trivial callee); ~0.003% of a 500ms model call. Run python benchmarks/overhead.py.

Posture ladder

Nyx walks a trust ladder, set via mode (or NYX_MODE):

The global mode is a master switch over per-rule modes:

Global mode Behavior
observe (default) decisions evaluated + recorded on each event; nothing acted on, nothing shadow-tagged
shadow every rule forced to shadow: would-act events tagged + rolled up, nothing acted on
enforce per-rule honored — rules with mode="enforce" act; rules left in mode="shadow" are tagged would-act

Each rule carries its own mode (shadow/enforce) and fail (open/closed), so you can flip one rule live while the rest stay in shadow. Gate actions: block, redact (mask args before the call), modify, and hold (synchronous approval via a registered approver).

Roadmap

Feature freeze — the umbrella merge is the single active workstream. New features are frozen in both products while ASPM + ADR converge into one repo, one design system, and one security graph. The merged roadmap (merge phases R1–R5 / P1–P5 + both product backlogs) is docs/roadmap.md.

The live, canonical roadmap is the Nyx Roadmap project — that board is the source of truth for the current item list, status, and priorities. ADR phases to date:

  • Phase 1–3 ✅ — single-language spine · correlation & attribution · policy in shadow
  • Phase 4 🟡 — enforcement: per-rule modes, block/redact/modify/hold, engine split, MCP (client + server) / Anthropic / Bedrock / Vertex / LlamaIndex / CrewAI / AutoGen / aiohttp (next: Node/TS stack)
  • Phase 5 ✅ — intelligence: behavioral baselines (per-agent novelty — NYX_BASELINE=1), criticality tagging (NYX_AGENT_CRITICALITY / NYX_AGENT_FUNCTION, findings ranked by blast radius), taint tracking (untrusted ingress → exfil sink, trace-scoped — NYX_TAINT=1), downstream emission schema (nyx.emission/1 → ASPM / AEGIS via POST /api/emit)
  • Phase 6 ✅ — agentic SIEM: smart policy from baselines (nyx.allowlist_rule + control-plane allowlist proposals with anti-poisoning), data-driven correlation/detection rules (lib/correlate.ts, multi-event SIEM over the stream — NYX_CORRELATION_RULES) with a durable alert store (Nyx as system-of-record — Alerts screen, dedup + acknowledge/resolve, survives event aging), Agentic Entity Behaviour Analytics (AEBA) (per-agent fleet risk profile, Entities screen) — built from reviewed plans in docs/plans/

See the project board for the detailed, current item list and status, and docs/plans/ for version-controlled, adversarially-reviewed implementation plans.

Shadow mode

nyx.install(mode="shadow")              # evaluate + tag + aggregate, never block
nyx.policy().add_precall(egress_allowlist)
...
nyx.shadow_summary()                     # {"total_would_act": 3, "by_policy": {...}, "examples": {...}}

Every non-allow decision is tagged onto its event (event["shadow"]) and rolled up; a shadow_summary event is emitted every shadow_summary_interval seconds and on shutdown. See examples/shadow_demo.py.

Quick start

import nyx

nyx.install()  # ConsoleSink: events to stderr
# or: nyx.install(endpoint="https://cp.example/ingest", api_key="...")

with nyx.run(agent_id="research-agent", session_id="sess-42"):
    ...  # run your agent; every event shares a trace_id

Everything is env-overridable for zero-code-change container drop-in: NYX_ENDPOINT, NYX_API_KEY, NYX_ENFORCE, NYX_CAPTURE_CONTENT, NYX_CAPTURE_STACK, NYX_SYNC, NYX_SERVICE, NYX_ENV.

Writing policy

Nyx core ships the mechanism; rules are registered on the shared engine.

from nyx import Finding, Decision, Rule

# a rule that ENFORCES (acts) while everything else stays shadow:
nyx.policy().add_rule(Rule(
    name="block-metadata",
    check=lambda ctx: Decision.block("cloud metadata egress", policy="block-metadata")
        if (ctx.request.get("host") or "").startswith("169.254.") else None,
    mode="enforce", fail="open",
))

# a rule that only watches (would-block logged, never acted on):
nyx.policy().add_rule(Rule(
    name="model-allowlist",
    check=lambda ctx: Decision.block("disallowed model", policy="model-allowlist")
        if ctx.request.get("model") not in ALLOWED else None,
    mode="shadow",
))

# HOLD requires synchronous approval:
nyx.set_approver(lambda ctx, decision: ask_human(ctx))   # -> bool

# detector: annotates the assembled event with findings (sees RAW content; never blocks)
def metadata_egress(event):
    host = (event.get("request") or {}).get("host") or ""
    if event["boundary"] == "effect" and host.startswith("169.254."):
        return Finding("egress.cloud_metadata", severity="critical",
                       message="agent reached cloud metadata endpoint",
                       data={"host": host}, atlas="AML.T0051", owasp="ASI05")
nyx.policy().add_detector(metadata_egress)

See it work

PYTHONPATH=. python examples/chain_demo.py    # prints the reconstructed trace tree
PYTHONPATH=. python examples/shadow_demo.py   # shadow-mode would-block rollup
PYTHONPATH=. python examples/enforce_demo.py  # per-rule: one rule live, one shadow
PYTHONPATH=. python examples/mcp_demo.py       # MCP client + server boundary (needs `pip install mcp`)
PYTHONPATH=. python benchmarks/overhead.py    # measures per-call overhead
PYTHONPATH=. python benchmarks/policy.py      # policy hot path: linear scan vs boundary index
python -m pytest -q                           # 77 tests (two real-MCP tests skip without the SDK)

# co-located engine split: run the engine, point the shim at it
python -m nyx.engine --socket /tmp/nyx.sock --forward console &
NYX_ENGINE_SOCKET=/tmp/nyx.sock python your_agent.py

chain_demo.py output (the trace tree the control plane reconstructs):

trace 2628fa…  (agent=research-agent session=sess-42)
  └─ [model_client]  chose=['fetch_url']                                  @ main (chain_demo.py:90)
  └─ [tool_dispatch]  tool=fetch_url                                      @ main (chain_demo.py:96)
    └─ [effect]  GET 169.254.169.254  !! critical:egress.cloud_metadata   @ tool_body (chain_demo.py:81)

Design guarantees

  • Do no harm. Extractors, hooks, and detectors are sandboxed; the only exception Nyx raises into agent code is NyxBlocked, and only under enforce=True.
  • Fail open. Errors in the enforcement path allow the call (fail_open=True).
  • No recursion. The reporter posts via stdlib urllib inside suppress_instrumentation(), so the effect boundary never observes Nyx's own traffic.
  • Privacy / residency. Metadata-only by default: payloads stay in the deployment boundary (hashed at ship time, opt in per deployment with capture_content=True); secret-keyed values are always redacted; identity is recorded as a fingerprint hash, never the credential.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nyx_monitor-0.1.0.tar.gz (201.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nyx_monitor-0.1.0-py3-none-any.whl (50.5 kB view details)

Uploaded Python 3

File details

Details for the file nyx_monitor-0.1.0.tar.gz.

File metadata

  • Download URL: nyx_monitor-0.1.0.tar.gz
  • Upload date:
  • Size: 201.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for nyx_monitor-0.1.0.tar.gz
Algorithm Hash digest
SHA256 759534cfedb239036e7cb3a9199f6b0a8b31048c80239321fa6751405bc9899e
MD5 b3984b21be3e20e2d57639580c9a8a76
BLAKE2b-256 36b89bc0fd147976ec40c60823a8df03a92e941150c1a5d407829f72c9339354

See more details on using hashes here.

Provenance

The following attestation bundles were made for nyx_monitor-0.1.0.tar.gz:

Publisher: release.yml on kgalappatti-aegis/Nyx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file nyx_monitor-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nyx_monitor-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 50.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for nyx_monitor-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 da7b2803bbf0adc79b55d49d05fc662c3cf851b70de5dd0c3004347c089f0191
MD5 671ddaca838e04298f88d6ccc1389a60
BLAKE2b-256 4371cfbbdde162588b95d8ec84f5323b7bbe5e60c28b2542f2faa8b466d94c17

See more details on using hashes here.

Provenance

The following attestation bundles were made for nyx_monitor-0.1.0-py3-none-any.whl:

Publisher: release.yml on kgalappatti-aegis/Nyx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page