Back to skill

Security audit

NOMOS Decision Engine

Security checks for vulnerabilities and agentic risk

Overview

The skill is not evidently malicious, but its enterprise API claims tenant isolation while storing and retrieving key records globally, which is a serious concern for shared deployments.

Treat this as suitable only for isolated research, local demos, or carefully single-tenant deployments until tenant enforcement and the identity endpoint are fixed. Do not expose it as a shared enterprise API or rely on its tenant-isolation claims without adding tenant columns, tenant-scoped queries, strict claim-derived tenant resolution, and tests proving tenant A cannot read or mutate tenant B data.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/second_perspective/api/main.py:82
Finding

Missing Tenant Enforcement Enables Cross-Tenant Data Access and Mutation

Content
View full analysis

Vulnerability Details

File Location: src/second_perspective/api/main.py:82-88; src/second_perspective/persistence/postgres.py:25-247; src/second_perspective/repository.py:31-66; src/second_perspective/hub/repository.py:24-75
Vulnerability Type: Broken tenant isolation / insecure direct object reference
Risk Level: High

Vulnerable Code

The tenant middleware trusts the caller-supplied tenant header before consulting verified OIDC claims:

python
tenant_id = request.headers.get(TENANT_HEADER)
if not tenant_id and authz_enforced():
    claims = getattr(request.state, "oidc_claims", None)
    tenant_id = resolve_tenant_from_claims(claims)
token = None
if tenant_id:
    token = set_tenant(tenant_id)

However, the PostgreSQL decision repository does not include the active tenant in its storage or lookup operations:

python
def get(self, decision_id: str) -> DecisionRecord | None:
    with self._lock:
        with self._conn() as conn, conn.cursor() as cur:
            cur.execute(
                "SELECT body FROM nomos_decisions WHERE decision_id = %s ORDER BY revision DESC LIMIT 1",
                (decision_id,),
            )
            row = cur.fetchone()
            if row is None:
                return None
            record = DecisionRecord.model_validate(json.loads(row["body"]))
            history = self.history(decision_id)
            if history and not verify_chain(history):
                raise ValueError(f"integrity verification failed for {decision_id}")
            return record

def history(self, decision_id: str) -> list[DecisionRecord]:
    with self._lock:
        with self._conn() as conn, conn.cursor() as cur:
            cur.execute(
                "SELECT body FROM nomos_decisions WHERE decision_id = %s ORDER BY revision ASC",
                (decision_id,),
            )
            rows = cur.fetchall()
            reco
...[truncated 5490 chars]
Remediation
View remediation

Remediation Suggestions

  1. Derive the tenant exclusively from verified identity claims when OIDC authorization is active. Do not allow an untrusted X-Tenant-Id header to override a verified tenant claim.
  2. If header-based tenant selection is required for service integrations, restrict it to a separately authenticated and explicitly authorized administrative mechanism.
  3. Add tenant_id to every decision, report, and session write.
  4. Include tenant_id = %s in every repository lookup, history query, update, revision check, and deletion operation.
  5. Change uniqueness and primary-key constraints to include tenant identity where identifiers are not globally unique, such as (tenant_id, decision_id, revision).
  6. Key in-memory repositories by (tenant_id, object_id) and obtain the tenant from get_tenant() at every repository boundary.
  7. Reject requests with no resolved tenant in multi-tenant production mode rather than silently using the global empty tenant.
  8. Add integration tests proving that credentials for tenant A cannot read, update, approve, or advance objects belonging to tenant B, even when object identifiers are known.
  9. Ensure migrations not only create tenant columns but also update runtime queries to populate and enforce them.

T09 · Insecure Skill Coding Practices

Warning
Location
src/second_perspective/api/main.py:164
Finding

Unauthenticated Identity Endpoint Treats Arbitrary Bearer Tokens as Valid API-Key Identities

Content
View full analysis

Vulnerability Details

File Location: src/second_perspective/api/main.py:164-197, 228-230
Vulnerability Type: Authentication state spoofing
Risk Level: Medium

Vulnerable Code

python
def _build_identity_response(authorization: str | None = None) -> dict:
    """Build a lightweight identity snapshot for the /auth/me endpoint.

    When OIDC is configured, the token is fully verified (signature, expiry,
    audience, issuer) before any claim is returned. Unverified claims are never
    exposed, so a forged JWT cannot impersonate an identity via this endpoint.
    """
    if not authorization:
        return {"mode": "none", "subject": "anonymous"}
    scheme, _, supplied = authorization.partition(" ")
    if scheme.casefold() != "bearer" or not supplied:
        return {"mode": "none", "subject": "anonymous"}
    oidc_issuer = os.getenv("SP_OIDC_ISSUER", "").strip()
    if oidc_issuer:
        try:
            from .security import _get_oidc_config, _verify_oidc_token

            config = _get_oidc_config()
            if config is not None:
                claims = _verify_oidc_token(supplied, config)
                if claims is not None:
                    return {
                        "mode": "oidc",
                        "issuer": oidc_issuer,
                        "subject": claims.get("sub", ""),
                        "name": claims.get("preferred_username", claims.get("name", "")),
                        "email": claims.get("email", ""),
                        "groups": claims.get("groups", []),
                    }
        except Exception:
            pass
    return {"mode": "api_key", "subject": "bearer-authenticated"}

The route does not use the normal authentication dependency:

python
@app.get("/v1/auth/me", operation_id="authWhoAmI")
def auth_me(authorization: str | None = Header(default=None)) -> dict:
    return _build_id
...[truncated 2122 chars]
Remediation
View remediation

Remediation Suggestions

  1. Protect /v1/auth/me with Depends(verify_api_key) or a dependency that returns the verified authentication principal.
  2. Return API-key mode only after comparing the supplied token with SP_API_KEY.
  3. Use a constant-time comparison such as secrets.compare_digest for API-key validation.
  4. If OIDC verification fails, return HTTP 401 Unauthorized; do not fall back to API-key identity unless the same token separately passes API-key validation.
  5. Refactor authentication so token verification occurs once and produces a typed principal consumed by both authorization checks and the identity endpoint.
  6. Add tests covering arbitrary bearer values, expired OIDC tokens, malformed JWTs, incorrect API keys, and valid tokens for each supported authentication mode.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (144)

Tainted flow: 'config_url' from os.getenv (line 98, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · src/second_perspective/api/security.py (reported line 100)May include surrounding context.

python
config_url = f"{issuer.rstrip('/')}/.well-known/openid-configuration"
    try:
        resp = requests.get(config_url, timeout=5)
        resp.raise_for_status()
        data = resp.json()
        return {

Hidden Instructions

High
Category
Prompt Injection
Confidence
60% confidence
Finding

Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Content

Scanner excerpt · LICENSE (reported line 1)May include surrounding context.

text
# 软件授权协议 / Software License Agreement

**版本 Version 1.2 | 生效日期 Effective: 2026-10-14**

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The skill markets deterministic decisioning, but also discloses optional external LLM API use, local file IO, and evolution proposal workflows that materially broaden data handling and outbound communication. Even if optional, these behaviors affect confidentiality and trust assumptions, especially in an enterprise context handling decision records and secrets via environment variables.

Content

No source excerpt is available for this finding.