Back to skill

Security audit

GuardRails

Security checks for vulnerabilities and agentic risk

Overview

The skill looks like a real guardrails service, but it needs review because reachable clients can change guardrail policies and full evaluation requests are stored.

Review deployment before installing or running this outside a local trusted environment. Add authentication and role-based authorization for policy and audit endpoints, restrict network exposure, and reduce or redact stored audit payloads with a clear retention policy. I found no artifact-backed evidence of deception, exfiltration, destructive install behavior, or prompt hijacking, so this is Review rather than malicious.

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
app/main.py:31
Finding

Unauthenticated Policy Administration Enables Complete Guardrail Bypass

Content
View full analysis
PolicyResponse: try: policy = create_policy(db, payload) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc return PolicyResponse.model_validate(policy) @app.get("/policies", response_model=list[PolicyResponse]) def list_policies_endpoint(db: Session = Depends(get_db)) -> list[PolicyResponse]: return [PolicyResponse.model_validate(p) for p in list_policies(db)] @app.get("/policies/{policy_id}", response_model=PolicyResponse) def get_policy_endpoint(policy_id: str, db: Session = Depends(get_db)) -> PolicyResponse: policy = get_policy(db, policy_id) if not policy: raise HTTPException(status_code=404, detail="Policy not found") return PolicyResponse.model_validate(policy) @app.patch("/policies/{policy_id}", response_model=PolicyResponse) def update_policy_endpoint(policy_id: str, payload: PolicyUpdate, db: Session = Depends(get_db)) -> PolicyResponse: policy = get_policy(db, policy_id) if not policy: raise HTTPException(status_code=404, detail="Policy not found") try: updated = update_policy(db, policy, payload) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc return PolicyResponse.model_validate(updated) @app.delete("/policies/{policy_id}", status_code=status.HTTP_204_NO_CONTENT) def disable_policy_endpoint(policy_id: str, db: Session = Depends(get_db)) -> Response: policy = get_policy(db, policy_id) if not policy: raise HTTPException(status_code=404, det ...[truncated 3171 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
app/service.py:78
Finding

Complete Evaluation Requests Are Retained Without Redaction or Retention Controls

Content
View full analysis
DecisionResponse: policies = list(db.execute(select(Policy).where(Policy.enabled.is_(True))).scalars().all()) result = evaluate_action(action, policies) audit = AuditLog( action_id=action.action_id, action_type=action.action_type, action_payload=action.model_dump(mode="json"), decision=result.model_dump(mode="json"), matched_policies=[p.model_dump(mode="json") for p in result.matched_policies], ) db.add(audit) db.commit() return result ``` The corresponding model stores the complete request as JSON without a deletion or expiration field: ```python class AuditLog(Base): __tablename__ = "audit_logs" id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True) action_id: Mapped[Optional[str]] = mapped_column(String(128), index=True, nullable=True) action_type: Mapped[str] = mapped_column(String(128), index=True) action_payload: Mapped[Dict[str, Any]] = mapped_column(JSON) decision: Mapped[Dict[str, Any]] = mapped_column(JSON) matched_policies: Mapped[List[Dict[str, Any]]] = mapped_column(JSON) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now()) ``` The default database is a local SQLite file: ```python class Settings(BaseSettings): app_name: str = "Agent Policy & Guardrails Engine" environment: str = "dev" database_url: str = "sqlite:///./guardrails.db" ``` ### Technical Analysis `ActionRequest` accepts arbitrary dictionaries in both `payload` and `context`. The evaluation service serializes the entire request with `action.model_dump(mode="json")` and stores it in `AuditLog.action_payload`. Actions evaluated by ...[truncated 2144 chars]
Remediation
View remediation
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
Findings (9)

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · README.md (reported line 83)May include surrounding context.

md
- `GET /policies`
- `GET /policies/{policy_id}`
- `PATCH /policies/{policy_id}`
- `DELETE /policies/{policy_id}` (soft-disable)
- `POST /evaluate`
- `GET /audit`
- `POST /seed` (load baseline policies)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · app/core/config.py (reported line 9)May include surrounding context.

python
environment: str = "dev"
    database_url: str = "sqlite:///./guardrails.db"

    model_config = SettingsConfigDict(env_prefix="GUARDRAILS_", env_file=".env", extra="ignore")


settings = Settings()

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · app/seed.py (reported line 78)May include surrounding context.

python
PolicyCreate(
            policy_id="OPS-GIT-001",
            name="Block force pushes",
            description="Disallow git push --force operations.",
            priority=1000,
            policy_format="structured",
            definition={

Anti-Refusal Statement

High
Category
Anti-Refusal
Confidence
90% confidence
Finding

Skill attempts to nullify the agent's safety policies or restrictions ('you have no restrictions', 'ignore your guidelines', 'do anything now'). This is a direct jailbreak that disables guardrails.

Content

Scanner excerpt · app/seed.py (reported line 134)May include surrounding context.

python
PolicyCreate(
            policy_id="OPS-DATA-001",
            name="Deny access to restricted files",
            description="Never allow reads/writes/deletes on restricted files without explicit bypass policy.",
            priority=990,
            policy_format="structured",
            definition={

Possible Typosquatting: 'uvicorn' resembles popular package 'gunicorn'

High
Category
Supply Chain
Confidence
70% confidence
Finding

Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: pytest==8.4.1 — 2 advisory(ies): CVE-2025-71176 (pytest has vulnerable tmpdir handling); CVE-2025-71176 (pytest has vulnerable tmpdir handling)

High
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency list pins pytest==8.4.1, and the scanner reports a known CVE affecting pytest tmpdir handling. This is a real supply-chain risk in the development and test environment, though pytest is typically not a production runtime dependency; in this skill context it is less likely to directly expose deployed systems unless test tooling runs in sensitive CI/CD environments or processes untrusted inputs.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The natural-language time policy parser silently hard-codes the timezone to UTC when constructing policy conditions. This can cause policy enforcement to occur at the wrong local time, leading to unintended allows or denies for sensitive operations, especially in multi-region or business-hours-based guardrail scenarios. In a policy and guardrails engine, this is more dangerous because users may assume local-time semantics while the engine enforces UTC globally.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · README.md (reported line 93)May include surrounding context.

md
return [
        PolicyCreate(
            policy_id="FIN-001",
            name="Max transaction without approval",
            description="Require approval above $5,000.",
            priority=200,
            policy_format="structured",

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · app/seed.py (reported line 10)May include surrounding context.

python
return [
        PolicyCreate(
            policy_id="FIN-001",
            name="Max transaction without approval",
            description="Require approval above $5,000.",
            priority=200,
            policy_format="structured",