[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6CDMYC16K0MFGEEXK3NE985":3,"skill-same:01M6CDMYC16K0MFGEEXK3NE985":91},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":22,"publishedAt":52,"linkOnly":53,"markdownContent":54,"markdownBody":55,"frontMatter":56,"refName":33,"commitSha":65,"skillDirectory":66,"forksCount":67,"repositoryHtmlUrl":68,"repositoryHomepageUrl":6,"ownerHtmlUrl":69,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":70,"install":71,"resources":84},"01M6CDMYC16K0MFGEEXK3NE985","ai-agent-security",null,"Secure AI agents against prompt injection, tool abuse, and data exfiltration with defense-in-depth controls.","boisenoise\u002Fskills-collections","boisenoise","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F193180?v=4","01M6CDBDQK6BDN55ZMA6B6PKBM","01M6CDBDVSJ3JPTBYN26FZ7TZK",12,"MIT","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-ai-agent-security\u002FSKILL.md",[17],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000023","Skill与智能体开发","SCENARIO","使用场景",[23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],"security","ai agent","ai agent security","agent security","vault","2026","relevant","scripts","scope","active","main","community","agent-skills","tooling","only","devops","prompt","tool","devops-security","exfiltration","defense-in-depth","https","license","assessment","secure","ai agents","github","safe","prompt injection","2026-11-10 10:12:30",false,"---\nname: ai-agent-security\ndescription: Secure AI agents against prompt injection, tool abuse, and data exfiltration\n  with defense-in-depth controls.\ncategory: security\nrisk: safe\nsource: https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\nsource_repo: BagelHole\u002FDevOps-Security-Agent-Skills\nsource_type: community\ndate_added: '2026-09-20'\nlicense: MIT\nlicense_source: https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\u002Fblob\u002Fmain\u002FLICENSE\ncompatibility: Requires the relevant security tooling (scanners, vault CLIs) and an\n  authorized scope for any active assessment. Docs-only; helper scripts and templates\n  not bundled.\nmetadata:\n  author: devops-skills\n  version: '2.0'\n---\n\n# AI Agent Security\n\nProtect agentic AI systems from adversarial input, unsafe tool execution, data leakage, and privilege abuse with layered security controls.\n\nThese are partial design sketches, not a working security boundary. Regexes\u002Fclassifiers have false positives and false negatives; prompt text cannot grant permissions. Enforce tenant identity, resource scope and approved actions in the tool service using authenticated server-side context. Input signing authenticates origin, not the safety of signed content. Bind approvals to the exact operation\u002Farguments and recheck immediately before execution. Test failure paths and concurrency before production use.\n\n## Prerequisites\n\n- Python 3.10+ for guardrail code examples\n- Docker or Podman for sandbox execution\n- OpenTelemetry collector for audit logging\n- Familiarity with your agent framework (LangChain, CrewAI, Autogen, custom)\n- Access to policy engine (OPA\u002FCedar) for permission boundaries\n\n## Threat Model — STRIDE for AI Agents\n\nAI agents introduce a unique threat surface. Apply STRIDE specifically to agentic components:\n\n| Threat | Agent-Specific Example | Control |\n|--------|----------------------|---------|\n| **Spoofing** | Attacker crafts input that mimics a trusted internal tool response | Signed tool responses, HMAC verification |\n| **Tampering** | Prompt injection modifies agent reasoning mid-chain | Input validation, prompt armoring |\n| **Repudiation** | Agent takes destructive action with no audit trail | Immutable structured logging |\n| **Information Disclosure** | Agent leaks PII, secrets, or internal architecture in responses | Output filtering, content classifiers |\n| **Denial of Service** | Adversarial prompt causes infinite tool loops or token exhaustion | Rate limits, token budgets, circuit breakers |\n| **Elevation of Privilege** | Agent escalates from read-only to write via chained tool calls | RBAC per tool, least-privilege scoping |\n\n### Key Threat Categories\n\n**Prompt Injection** — Untrusted content (user input, web scrapes, document contents) manipulates the agent's system prompt or reasoning chain to execute unintended actions.\n\n**Tool Abuse** — The agent calls tools in sequences or with parameters the designer did not anticipate, achieving effects beyond its intended scope.\n\n**Data Exfiltration** — The agent encodes sensitive data (credentials, PII, internal IPs) into its responses, tool calls, or outbound HTTP requests.\n\n**Cross-Tenant Leakage** — In multi-tenant deployments, context from one tenant's session bleeds into another through shared memory, vector stores, or cache.\n\n**Privilege Escalation** — The agent chains low-privilege tool calls to achieve high-privilege outcomes (e.g., read config -> extract credentials -> call admin API).\n\n## Input Validation\n\nEvery input to an agent must be sanitized before it reaches the model or any tool. This includes user messages, tool outputs being fed back, and retrieved documents.\n\n### Prompt Injection Detection\n\n```python\nimport re\nfrom dataclasses import dataclass\nfrom enum import Enum\n\nclass RiskLevel(Enum):\n    LOW = \"low\"\n    MEDIUM = \"medium\"\n    HIGH = \"high\"\n    CRITICAL = \"critical\"\n\n@dataclass\nclass ValidationResult:\n    is_safe: bool\n    risk_level: RiskLevel\n    matched_rules: list[str]\n    sanitized_input: str\n\nINJECTION_PATTERNS = [\n    (r\"ignore\\s+(all\\s+)?(previous|prior|above)\\s+(instructions|prompts|rules)\", \"instruction_override\"),\n    (r\"you\\s+are\\s+now\\s+(a|an|the)\\s+\", \"role_hijack\"),\n    (r\"system\\s*:\\s*\", \"system_prompt_inject\"),\n    (r\"\u003C\\|?(system|im_start|endoftext)\\|?>\", \"control_token_inject\"),\n    (r\"\\[INST\\]|\\[\\\u002FINST\\]|\u003C\u003CSYS>>\", \"template_inject\"),\n    (r\"(?:execute|run|eval)\\s*\\(\", \"code_execution_attempt\"),\n    (r\"(?:curl|wget|nc|ncat)\\s+\", \"network_command_inject\"),\n    (r\"(?:rm\\s+-rf|mkfs|dd\\s+if=|chmod\\s+777)\", \"destructive_command\"),\n    (r\"(?:\\\u002Fetc\\\u002Fpasswd|\\\u002Fetc\\\u002Fshadow|\\.env\\b|\\.ssh\\\u002F)\", \"path_traversal\"),\n    (r\"(?:BEGIN\\s+(?:RSA|DSA|EC)\\s+PRIVATE\\s+KEY)\", \"secret_exfil_attempt\"),\n]\n\ndef validate_agent_input(user_input: str, max_length: int = 4096) -> ValidationResult:\n    \"\"\"Validate and sanitize input before passing to agent.\"\"\"\n    matched = []\n    risk = RiskLevel.LOW\n\n    # Length check\n    if len(user_input) > max_length:\n        matched.append(\"input_too_long\")\n        risk = RiskLevel.MEDIUM\n\n    # Null byte and control character removal\n    sanitized = user_input.replace(\"\\x00\", \"\")\n    sanitized = re.sub(r\"[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f]\", \"\", sanitized)\n\n    # Pattern matching\n    for pattern, rule_name in INJECTION_PATTERNS:\n        if re.search(pattern, sanitized, re.IGNORECASE):\n            matched.append(rule_name)\n            risk = RiskLevel.HIGH\n\n    # Stacked injection detection (multiple suspicious patterns)\n    if len(matched) >= 3:\n        risk = RiskLevel.CRITICAL\n\n    is_safe = not matched  # heuristic result only; never authorization\n\n    return ValidationResult(\n        is_safe=is_safe,\n        risk_level=risk,\n        matched_rules=matched,\n        sanitized_input=sanitized[:max_length] if is_safe else \"\",\n    )\n```\n\n### Content Classification Middleware\n\nUse a lightweight classifier as middleware before the agent processes any input:\n\n```python\nfrom functools import wraps\nfrom typing import Callable\n\ndef input_guard(validator: Callable = validate_agent_input):\n    \"\"\"Decorator that guards agent entry points against unsafe input.\"\"\"\n    def decorator(func):\n        @wraps(func)\n        async def wrapper(user_input: str, *args, **kwargs):\n            result = validator(user_input)\n\n            if not result.is_safe:\n                await log_security_event(\n                    event=\"input_blocked\",\n                    risk=result.risk_level.value,\n                    rules=result.matched_rules,\n                    input_hash=hashlib.sha256(user_input.encode()).hexdigest(),\n                )\n                raise InputRejectedError(\n                    f\"Input blocked: matched {result.matched_rules}\"\n                )\n\n            return await func(result.sanitized_input, *args, **kwargs)\n        return wrapper\n    return decorator\n\n# Usage\n@input_guard()\nasync def handle_user_message(message: str, session_id: str, **kwargs):\n    \"\"\"Process a validated user message through the agent.\"\"\"\n    flags = kwargs.get(\"_security_flags\", [])\n    if flags:\n        # Route to sandboxed execution path\n        return await agent.run_sandboxed(message, session_id)\n    return await agent.run(message, session_id)\n```\n\n## Tool Execution Sandboxing\n\nIsolate untrusted code in a sandbox appropriate to the threat model. Containers share the host kernel and do not replace tool-service authorization. Do not mount the Docker socket or host credentials; run as a non-root user and restrict mounts and egress. NET_BIND_SERVICE permits low-port binding, not network access.\n\n### Docker Sandbox Configuration\n\n```yaml\n# docker-compose.agent-sandbox.yml\nversion: \"3.8\"\n\nservices:\n  agent-sandbox:\n    image: agent-tools:latest\n    read_only: true\n    security_opt:\n      - no-new-privileges:true\n      - seccomp:seccomp-profile.json\n    cap_drop:\n      - ALL\n    tmpfs:\n      - \u002Ftmp:size=64M,noexec,nosuid\n    mem_limit: 512m\n    cpus: \"0.5\"\n    pids_limit: 64\n    networks:\n      - sandbox-net\n    environment:\n      - TOOL_TIMEOUT=30 # application must enforce this; env vars alone do nothing\n      - MAX_OUTPUT_BYTES=65536\n    volumes:\n      - type: bind\n        source: .\u002Ftool-workspace\n        target: \u002Fworkspace\n        read_only: false\n    dns:\n      - 127.0.0.1           # Block external DNS by default\n\nnetworks:\n  sandbox-net:\n    driver: bridge\n    internal: true           # No external network access\n```\n\n### gVisor Runtime for Stronger Isolation\n\n```bash\n# Install gVisor runsc runtime\ncurl -fsSL https:\u002F\u002Fgvisor.dev\u002Farchive.key | sudo gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fgvisor-archive-keyring.gpg\necho \"deb [signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fgvisor-archive-keyring.gpg] https:\u002F\u002Fstorage.googleapis.com\u002Fgvisor\u002Freleases release main\" | \\\n  sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fgvisor.list\nsudo apt-get update && sudo apt-get install -y runsc\n\n# Configure Docker to use gVisor\n# Illustrative fragment only: merge into a backed-up daemon.json, validate,\n# and schedule the disruptive Docker restart. Do not overwrite existing settings.\ncat \u003C\u003C'EOF' > runsc-daemon-fragment.json\n{\n  \"runtimes\": {\n    \"runsc\": {\n      \"path\": \"\u002Fusr\u002Fbin\u002Frunsc\",\n      \"runtimeArgs\": [\n        \"--network=none\",\n        \"--directfs=false\"\n      ]\n    }\n  }\n}\nEOF\nsudo systemctl restart docker\n\n# Run agent sandbox with gVisor\ndocker run --runtime=runsc --rm --network=none --cap-drop=ALL --security-opt=no-new-privileges --user=65534:65534 \\\n  --read-only \\\n  --memory=512m \\\n  --cpus=0.5 \\\n  --pids-limit=64 \\\n  agent-tools:latest \\\n  python \u002Ftools\u002Fexecute.py --tool=\"$TOOL_NAME\" --args=\"$TOOL_ARGS\"\n```\n\n### Tool Allowlist Sketch (Incomplete)\n\nThis sketch fails closed for approval-gated operations but is not a production gatekeeper. Replace cross-argument regex checks with tool-specific schemas: resolve paths under an OS-enforced root (including symlinks), use read-only scoped DB credentials and parameterized query APIs, and parse\u002Fresolve URLs with redirect\u002FDNS\u002FIP egress enforcement. A Python import denylist is not a sandbox. Counters need atomic tenant\u002Fsession-scoped storage; this object alone is neither concurrent-safe nor tenant isolation.\n\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass ToolPolicy:\n    name: str\n    allowed_args: dict[str, type]     # parameter name -> expected type\n    max_calls_per_session: int = 10\n    requires_approval: bool = False\n    allowed_patterns: list[str] = field(default_factory=list)\n    blocked_patterns: list[str] = field(default_factory=list)\n\nTOOL_ALLOWLIST: dict[str, ToolPolicy] = {\n    \"read_file\": ToolPolicy(\n        name=\"read_file\",\n        allowed_args={\"path\": str},\n        max_calls_per_session=20,\n        allowed_patterns=[r\"^\u002Fworkspace\u002F\", r\"^\u002Fdata\u002Fpublic\u002F\"],\n        blocked_patterns=[r\"\\.env$\", r\"\\.key$\", r\"\\.pem$\", r\"\u002Fetc\u002F\", r\"\u002Fproc\u002F\"],\n    ),\n    \"run_query\": ToolPolicy(\n        name=\"run_query\",\n        allowed_args={\"sql\": str, \"database\": str},\n        max_calls_per_session=5,\n        allowed_patterns=[r\"^SELECT\\s\", r\"^EXPLAIN\\s\"],\n        blocked_patterns=[r\"\\bDROP\\b\", r\"\\bDELETE\\b\", r\"\\bUPDATE\\b\", r\"\\bINSERT\\b\", r\"\\bALTER\\b\"],\n    ),\n    \"http_request\": ToolPolicy(\n        name=\"http_request\",\n        allowed_args={\"url\": str, \"method\": str},\n        max_calls_per_session=10,\n        requires_approval=True,\n        allowed_patterns=[r\"^https:\u002F\u002Fapi\\.internal\\.\"],\n        blocked_patterns=[r\"^https?:\u002F\u002F169\\.254\\.\", r\"^https?:\u002F\u002Fmetadata\\.google\\.\"],\n    ),\n    \"execute_code\": ToolPolicy(\n        name=\"execute_code\",\n        allowed_args={\"code\": str, \"language\": str},\n        max_calls_per_session=3,\n        requires_approval=True,\n        blocked_patterns=[r\"import\\s+subprocess\", r\"import\\s+os\", r\"__import__\", r\"eval\\(\", r\"exec\\(\"],\n    ),\n}\n\nclass ToolGatekeeper:\n    def __init__(self, allowlist: dict[str, ToolPolicy]):\n        self.allowlist = allowlist\n        self.call_counts: dict[str, int] = {}\n\n    async def authorize(self, tool_name: str, args: dict) -> bool:\n        if tool_name not in self.allowlist:\n            await log_security_event(\n                event=\"tool_denied_not_in_allowlist\",\n                tool=tool_name,\n            )\n            return False\n\n        policy = self.allowlist[tool_name]\n\n        # Check call count\n        count = self.call_counts.get(tool_name, 0)\n        if count >= policy.max_calls_per_session:\n            await log_security_event(\n                event=\"tool_denied_rate_limit\",\n                tool=tool_name,\n                count=count,\n            )\n            return False\n\n        # Validate argument types\n        for arg_name, expected_type in policy.allowed_args.items():\n            if arg_name not in args or not isinstance(args[arg_name], expected_type):\n                return False\n\n        if set(args) != set(policy.allowed_args):\n            return False\n        if policy.requires_approval:\n            return False  # until an authenticated, argument-bound approval service is integrated\n\n        # Pattern checks are heuristics, not path\u002FSQL\u002FURL\u002Fcode authorization.\n        # Check patterns against all string arguments\n        for arg_value in args.values():\n            if not isinstance(arg_value, str):\n                continue\n            # Must match at least one allowed pattern (if any defined)\n            if policy.allowed_patterns:\n                if not any(re.search(p, arg_value, re.IGNORECASE) for p in policy.allowed_patterns):\n                    return False\n            # Must not match any blocked pattern\n            if any(re.search(p, arg_value, re.IGNORECASE) for p in policy.blocked_patterns):\n                await log_security_event(\n                    event=\"tool_denied_blocked_pattern\",\n                    tool=tool_name,\n                    arg_value_hash=hashlib.sha256(arg_value.encode()).hexdigest(),\n                )\n                return False\n\n        self.call_counts[tool_name] = count + 1\n        return True\n```\n\n\n## Contents\n\n- [Permission Boundaries](references\u002Fdetails.md)\n- [Output Filtering](references\u002Fdetails.md)\n- [Audit Logging](references\u002Fdetails.md)\n- [Rate Limiting and Abuse Prevention](references\u002Fdetails.md)\n- [Kill Switches and Circuit Breakers](references\u002Fdetails.md)\n- [Red Team Checklist](references\u002Fdetails.md)\n- [Incident Response Playbook](references\u002Fdetails.md)\n- [Troubleshooting](references\u002Fdetails.md)\n- [Best Practices](references\u002Fdetails.md)\n- [Related Skills](references\u002Fdetails.md)\n\n## When to Use This Skill\n\nUse this skill when:\n- Building AI agents that invoke tools, APIs, or shell commands\n- Deploying agents with access to production databases, cloud accounts, or internal services\n- Hardening multi-tenant agent platforms against cross-tenant data leakage\n- Adding guardrails to autonomous coding agents or SRE bots\n- Designing approval workflows for high-risk agent actions\n- Conducting red-team exercises against agentic systems\n- Responding to incidents involving compromised or misbehaving agents\n\n## Limitations\n\n- Apply guidance only within authorized scope; test destructive steps in non-production first.\n- Docs-only import: upstream scripts and templates not bundled.\n\n### Example\n\n```bash\n# Read-only first: inventory before any active step.\nwhich \u003Ctool> && \u003Ctool> --help | head -n 20\n```\n\n> Adapted from [BagelHole\u002FDevOps-Security-Agent-Skills](https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills) (MIT); frontmatter, When to Use\u002FLimitations, and safety boundaries added for upstream compliance. Docs-only import: helper scripts and templates not bundled.\n","# AI Agent Security\n\nProtect agentic AI systems from adversarial input, unsafe tool execution, data leakage, and privilege abuse with layered security controls.\n\nThese are partial design sketches, not a working security boundary. Regexes\u002Fclassifiers have false positives and false negatives; prompt text cannot grant permissions. Enforce tenant identity, resource scope and approved actions in the tool service using authenticated server-side context. Input signing authenticates origin, not the safety of signed content. Bind approvals to the exact operation\u002Farguments and recheck immediately before execution. Test failure paths and concurrency before production use.\n\n## Prerequisites\n\n- Python 3.10+ for guardrail code examples\n- Docker or Podman for sandbox execution\n- OpenTelemetry collector for audit logging\n- Familiarity with your agent framework (LangChain, CrewAI, Autogen, custom)\n- Access to policy engine (OPA\u002FCedar) for permission boundaries\n\n## Threat Model — STRIDE for AI Agents\n\nAI agents introduce a unique threat surface. Apply STRIDE specifically to agentic components:\n\n| Threat | Agent-Specific Example | Control |\n|--------|----------------------|---------|\n| **Spoofing** | Attacker crafts input that mimics a trusted internal tool response | Signed tool responses, HMAC verification |\n| **Tampering** | Prompt injection modifies agent reasoning mid-chain | Input validation, prompt armoring |\n| **Repudiation** | Agent takes destructive action with no audit trail | Immutable structured logging |\n| **Information Disclosure** | Agent leaks PII, secrets, or internal architecture in responses | Output filtering, content classifiers |\n| **Denial of Service** | Adversarial prompt causes infinite tool loops or token exhaustion | Rate limits, token budgets, circuit breakers |\n| **Elevation of Privilege** | Agent escalates from read-only to write via chained tool calls | RBAC per tool, least-privilege scoping |\n\n### Key Threat Categories\n\n**Prompt Injection** — Untrusted content (user input, web scrapes, document contents) manipulates the agent's system prompt or reasoning chain to execute unintended actions.\n\n**Tool Abuse** — The agent calls tools in sequences or with parameters the designer did not anticipate, achieving effects beyond its intended scope.\n\n**Data Exfiltration** — The agent encodes sensitive data (credentials, PII, internal IPs) into its responses, tool calls, or outbound HTTP requests.\n\n**Cross-Tenant Leakage** — In multi-tenant deployments, context from one tenant's session bleeds into another through shared memory, vector stores, or cache.\n\n**Privilege Escalation** — The agent chains low-privilege tool calls to achieve high-privilege outcomes (e.g., read config -> extract credentials -> call admin API).\n\n## Input Validation\n\nEvery input to an agent must be sanitized before it reaches the model or any tool. This includes user messages, tool outputs being fed back, and retrieved documents.\n\n### Prompt Injection Detection\n\n```python\nimport re\nfrom dataclasses import dataclass\nfrom enum import Enum\n\nclass RiskLevel(Enum):\n    LOW = \"low\"\n    MEDIUM = \"medium\"\n    HIGH = \"high\"\n    CRITICAL = \"critical\"\n\n@dataclass\nclass ValidationResult:\n    is_safe: bool\n    risk_level: RiskLevel\n    matched_rules: list[str]\n    sanitized_input: str\n\nINJECTION_PATTERNS = [\n    (r\"ignore\\s+(all\\s+)?(previous|prior|above)\\s+(instructions|prompts|rules)\", \"instruction_override\"),\n    (r\"you\\s+are\\s+now\\s+(a|an|the)\\s+\", \"role_hijack\"),\n    (r\"system\\s*:\\s*\", \"system_prompt_inject\"),\n    (r\"\u003C\\|?(system|im_start|endoftext)\\|?>\", \"control_token_inject\"),\n    (r\"\\[INST\\]|\\[\\\u002FINST\\]|\u003C\u003CSYS>>\", \"template_inject\"),\n    (r\"(?:execute|run|eval)\\s*\\(\", \"code_execution_attempt\"),\n    (r\"(?:curl|wget|nc|ncat)\\s+\", \"network_command_inject\"),\n    (r\"(?:rm\\s+-rf|mkfs|dd\\s+if=|chmod\\s+777)\", \"destructive_command\"),\n    (r\"(?:\\\u002Fetc\\\u002Fpasswd|\\\u002Fetc\\\u002Fshadow|\\.env\\b|\\.ssh\\\u002F)\", \"path_traversal\"),\n    (r\"(?:BEGIN\\s+(?:RSA|DSA|EC)\\s+PRIVATE\\s+KEY)\", \"secret_exfil_attempt\"),\n]\n\ndef validate_agent_input(user_input: str, max_length: int = 4096) -> ValidationResult:\n    \"\"\"Validate and sanitize input before passing to agent.\"\"\"\n    matched = []\n    risk = RiskLevel.LOW\n\n    # Length check\n    if len(user_input) > max_length:\n        matched.append(\"input_too_long\")\n        risk = RiskLevel.MEDIUM\n\n    # Null byte and control character removal\n    sanitized = user_input.replace(\"\\x00\", \"\")\n    sanitized = re.sub(r\"[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f]\", \"\", sanitized)\n\n    # Pattern matching\n    for pattern, rule_name in INJECTION_PATTERNS:\n        if re.search(pattern, sanitized, re.IGNORECASE):\n            matched.append(rule_name)\n            risk = RiskLevel.HIGH\n\n    # Stacked injection detection (multiple suspicious patterns)\n    if len(matched) >= 3:\n        risk = RiskLevel.CRITICAL\n\n    is_safe = not matched  # heuristic result only; never authorization\n\n    return ValidationResult(\n        is_safe=is_safe,\n        risk_level=risk,\n        matched_rules=matched,\n        sanitized_input=sanitized[:max_length] if is_safe else \"\",\n    )\n```\n\n### Content Classification Middleware\n\nUse a lightweight classifier as middleware before the agent processes any input:\n\n```python\nfrom functools import wraps\nfrom typing import Callable\n\ndef input_guard(validator: Callable = validate_agent_input):\n    \"\"\"Decorator that guards agent entry points against unsafe input.\"\"\"\n    def decorator(func):\n        @wraps(func)\n        async def wrapper(user_input: str, *args, **kwargs):\n            result = validator(user_input)\n\n            if not result.is_safe:\n                await log_security_event(\n                    event=\"input_blocked\",\n                    risk=result.risk_level.value,\n                    rules=result.matched_rules,\n                    input_hash=hashlib.sha256(user_input.encode()).hexdigest(),\n                )\n                raise InputRejectedError(\n                    f\"Input blocked: matched {result.matched_rules}\"\n                )\n\n            return await func(result.sanitized_input, *args, **kwargs)\n        return wrapper\n    return decorator\n\n# Usage\n@input_guard()\nasync def handle_user_message(message: str, session_id: str, **kwargs):\n    \"\"\"Process a validated user message through the agent.\"\"\"\n    flags = kwargs.get(\"_security_flags\", [])\n    if flags:\n        # Route to sandboxed execution path\n        return await agent.run_sandboxed(message, session_id)\n    return await agent.run(message, session_id)\n```\n\n## Tool Execution Sandboxing\n\nIsolate untrusted code in a sandbox appropriate to the threat model. Containers share the host kernel and do not replace tool-service authorization. Do not mount the Docker socket or host credentials; run as a non-root user and restrict mounts and egress. NET_BIND_SERVICE permits low-port binding, not network access.\n\n### Docker Sandbox Configuration\n\n```yaml\n# docker-compose.agent-sandbox.yml\nversion: \"3.8\"\n\nservices:\n  agent-sandbox:\n    image: agent-tools:latest\n    read_only: true\n    security_opt:\n      - no-new-privileges:true\n      - seccomp:seccomp-profile.json\n    cap_drop:\n      - ALL\n    tmpfs:\n      - \u002Ftmp:size=64M,noexec,nosuid\n    mem_limit: 512m\n    cpus: \"0.5\"\n    pids_limit: 64\n    networks:\n      - sandbox-net\n    environment:\n      - TOOL_TIMEOUT=30 # application must enforce this; env vars alone do nothing\n      - MAX_OUTPUT_BYTES=65536\n    volumes:\n      - type: bind\n        source: .\u002Ftool-workspace\n        target: \u002Fworkspace\n        read_only: false\n    dns:\n      - 127.0.0.1           # Block external DNS by default\n\nnetworks:\n  sandbox-net:\n    driver: bridge\n    internal: true           # No external network access\n```\n\n### gVisor Runtime for Stronger Isolation\n\n```bash\n# Install gVisor runsc runtime\ncurl -fsSL https:\u002F\u002Fgvisor.dev\u002Farchive.key | sudo gpg --dearmor -o \u002Fusr\u002Fshare\u002Fkeyrings\u002Fgvisor-archive-keyring.gpg\necho \"deb [signed-by=\u002Fusr\u002Fshare\u002Fkeyrings\u002Fgvisor-archive-keyring.gpg] https:\u002F\u002Fstorage.googleapis.com\u002Fgvisor\u002Freleases release main\" | \\\n  sudo tee \u002Fetc\u002Fapt\u002Fsources.list.d\u002Fgvisor.list\nsudo apt-get update && sudo apt-get install -y runsc\n\n# Configure Docker to use gVisor\n# Illustrative fragment only: merge into a backed-up daemon.json, validate,\n# and schedule the disruptive Docker restart. Do not overwrite existing settings.\ncat \u003C\u003C'EOF' > runsc-daemon-fragment.json\n{\n  \"runtimes\": {\n    \"runsc\": {\n      \"path\": \"\u002Fusr\u002Fbin\u002Frunsc\",\n      \"runtimeArgs\": [\n        \"--network=none\",\n        \"--directfs=false\"\n      ]\n    }\n  }\n}\nEOF\nsudo systemctl restart docker\n\n# Run agent sandbox with gVisor\ndocker run --runtime=runsc --rm --network=none --cap-drop=ALL --security-opt=no-new-privileges --user=65534:65534 \\\n  --read-only \\\n  --memory=512m \\\n  --cpus=0.5 \\\n  --pids-limit=64 \\\n  agent-tools:latest \\\n  python \u002Ftools\u002Fexecute.py --tool=\"$TOOL_NAME\" --args=\"$TOOL_ARGS\"\n```\n\n### Tool Allowlist Sketch (Incomplete)\n\nThis sketch fails closed for approval-gated operations but is not a production gatekeeper. Replace cross-argument regex checks with tool-specific schemas: resolve paths under an OS-enforced root (including symlinks), use read-only scoped DB credentials and parameterized query APIs, and parse\u002Fresolve URLs with redirect\u002FDNS\u002FIP egress enforcement. A Python import denylist is not a sandbox. Counters need atomic tenant\u002Fsession-scoped storage; this object alone is neither concurrent-safe nor tenant isolation.\n\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass ToolPolicy:\n    name: str\n    allowed_args: dict[str, type]     # parameter name -> expected type\n    max_calls_per_session: int = 10\n    requires_approval: bool = False\n    allowed_patterns: list[str] = field(default_factory=list)\n    blocked_patterns: list[str] = field(default_factory=list)\n\nTOOL_ALLOWLIST: dict[str, ToolPolicy] = {\n    \"read_file\": ToolPolicy(\n        name=\"read_file\",\n        allowed_args={\"path\": str},\n        max_calls_per_session=20,\n        allowed_patterns=[r\"^\u002Fworkspace\u002F\", r\"^\u002Fdata\u002Fpublic\u002F\"],\n        blocked_patterns=[r\"\\.env$\", r\"\\.key$\", r\"\\.pem$\", r\"\u002Fetc\u002F\", r\"\u002Fproc\u002F\"],\n    ),\n    \"run_query\": ToolPolicy(\n        name=\"run_query\",\n        allowed_args={\"sql\": str, \"database\": str},\n        max_calls_per_session=5,\n        allowed_patterns=[r\"^SELECT\\s\", r\"^EXPLAIN\\s\"],\n        blocked_patterns=[r\"\\bDROP\\b\", r\"\\bDELETE\\b\", r\"\\bUPDATE\\b\", r\"\\bINSERT\\b\", r\"\\bALTER\\b\"],\n    ),\n    \"http_request\": ToolPolicy(\n        name=\"http_request\",\n        allowed_args={\"url\": str, \"method\": str},\n        max_calls_per_session=10,\n        requires_approval=True,\n        allowed_patterns=[r\"^https:\u002F\u002Fapi\\.internal\\.\"],\n        blocked_patterns=[r\"^https?:\u002F\u002F169\\.254\\.\", r\"^https?:\u002F\u002Fmetadata\\.google\\.\"],\n    ),\n    \"execute_code\": ToolPolicy(\n        name=\"execute_code\",\n        allowed_args={\"code\": str, \"language\": str},\n        max_calls_per_session=3,\n        requires_approval=True,\n        blocked_patterns=[r\"import\\s+subprocess\", r\"import\\s+os\", r\"__import__\", r\"eval\\(\", r\"exec\\(\"],\n    ),\n}\n\nclass ToolGatekeeper:\n    def __init__(self, allowlist: dict[str, ToolPolicy]):\n        self.allowlist = allowlist\n        self.call_counts: dict[str, int] = {}\n\n    async def authorize(self, tool_name: str, args: dict) -> bool:\n        if tool_name not in self.allowlist:\n            await log_security_event(\n                event=\"tool_denied_not_in_allowlist\",\n                tool=tool_name,\n            )\n            return False\n\n        policy = self.allowlist[tool_name]\n\n        # Check call count\n        count = self.call_counts.get(tool_name, 0)\n        if count >= policy.max_calls_per_session:\n            await log_security_event(\n                event=\"tool_denied_rate_limit\",\n                tool=tool_name,\n                count=count,\n            )\n            return False\n\n        # Validate argument types\n        for arg_name, expected_type in policy.allowed_args.items():\n            if arg_name not in args or not isinstance(args[arg_name], expected_type):\n                return False\n\n        if set(args) != set(policy.allowed_args):\n            return False\n        if policy.requires_approval:\n            return False  # until an authenticated, argument-bound approval service is integrated\n\n        # Pattern checks are heuristics, not path\u002FSQL\u002FURL\u002Fcode authorization.\n        # Check patterns against all string arguments\n        for arg_value in args.values():\n            if not isinstance(arg_value, str):\n                continue\n            # Must match at least one allowed pattern (if any defined)\n            if policy.allowed_patterns:\n                if not any(re.search(p, arg_value, re.IGNORECASE) for p in policy.allowed_patterns):\n                    return False\n            # Must not match any blocked pattern\n            if any(re.search(p, arg_value, re.IGNORECASE) for p in policy.blocked_patterns):\n                await log_security_event(\n                    event=\"tool_denied_blocked_pattern\",\n                    tool=tool_name,\n                    arg_value_hash=hashlib.sha256(arg_value.encode()).hexdigest(),\n                )\n                return False\n\n        self.call_counts[tool_name] = count + 1\n        return True\n```\n\n\n## Contents\n\n- [Permission Boundaries](references\u002Fdetails.md)\n- [Output Filtering](references\u002Fdetails.md)\n- [Audit Logging](references\u002Fdetails.md)\n- [Rate Limiting and Abuse Prevention](references\u002Fdetails.md)\n- [Kill Switches and Circuit Breakers](references\u002Fdetails.md)\n- [Red Team Checklist](references\u002Fdetails.md)\n- [Incident Response Playbook](references\u002Fdetails.md)\n- [Troubleshooting](references\u002Fdetails.md)\n- [Best Practices](references\u002Fdetails.md)\n- [Related Skills](references\u002Fdetails.md)\n\n## When to Use This Skill\n\nUse this skill when:\n- Building AI agents that invoke tools, APIs, or shell commands\n- Deploying agents with access to production databases, cloud accounts, or internal services\n- Hardening multi-tenant agent platforms against cross-tenant data leakage\n- Adding guardrails to autonomous coding agents or SRE bots\n- Designing approval workflows for high-risk agent actions\n- Conducting red-team exercises against agentic systems\n- Responding to incidents involving compromised or misbehaving agents\n\n## Limitations\n\n- Apply guidance only within authorized scope; test destructive steps in non-production first.\n- Docs-only import: upstream scripts and templates not bundled.\n\n### Example\n\n```bash\n# Read-only first: inventory before any active step.\nwhich \u003Ctool> && \u003Ctool> --help | head -n 20\n```\n\n> Adapted from [BagelHole\u002FDevOps-Security-Agent-Skills](https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills) (MIT); frontmatter, When to Use\u002FLimitations, and safety boundaries added for upstream compliance. Docs-only import: helper scripts and templates not bundled.\n",{"name":5,"risk":50,"source":57,"license":14,"category":23,"metadata":58,"date_added":61,"description":7,"source_repo":62,"source_type":34,"compatibility":63,"license_source":64},"https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills",{"author":59,"version":60},"devops-skills","2.0","2026-09-20","BagelHole\u002FDevOps-Security-Agent-Skills","Requires the relevant security tooling (scanners, vault CLIs) and an authorized scope for any active assessment. Docs-only; helper scripts and templates not bundled.","https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\u002Fblob\u002Fmain\u002FLICENSE","e8c4cb5cbafb600fab08ffdf4b23359c9f608d9d","skills\u002Fantigravity-ai-agent-security",3,"https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections","https:\u002F\u002Fgithub.com\u002Fboisenoise","2026-11-10 14:20:15",{"source":8,"skillName":5,"commands":72,"prompt":82,"zipAvailable":83},[73,76,79],{"tool":74,"command":75},"npx","npx skills add boisenoise\u002Fskills-collections --skill ai-agent-security",{"tool":77,"command":78},"bunx","bunx skills add boisenoise\u002Fskills-collections --skill ai-agent-security",{"tool":80,"command":81},"pnpm","pnpm dlx skills add boisenoise\u002Fskills-collections --skill ai-agent-security","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-ai-agent-security\u002FSKILL.md",true,[85],{"path":86,"resourceType":87,"resourceTypeDesc":88,"sizeBytes":89,"sourceHtmlUrl":90},"references\u002Fdetails.md","REFERENCE","参考文档",32686,"https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-ai-agent-security\u002Freferences\u002Fdetails.md",[92,120,142,167,186,209],{"skillNo":93,"name":94,"nameZh":6,"description":95,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":96,"licenseFileUrl":97,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":52},"01M6WNH92BHVFXHGPDZCPJ0AG0","web-access","Use Treg for public web or platform data only when existing search, browser and connected tools cannot cover the task, with explicit cost and data boundaries.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-web-access\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-web-access\u002FSKILL.md",[],[101,102,103,104,105,106,107,108,109,110,111,37,112,113,114,115,116,117,118,119,28],"web","access","web access","official","development","browser","search","data","Tools","read","fetch","youtube","free tools","platform","critical","free","cover","normal","when",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":96,"licenseFileUrl":124,"sourceHtmlUrl":125,"categories":126,"keywords":128,"publishedAt":52},"01M6WNF9XAYAB2CZDDJBAKNM93","treg","Use the Treg CLI or MCP catalog to discover, price and call authorized external tools with team-scoped credentials and a user-approved budget.","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-treg\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-treg\u002FSKILL.md",[127],{"categoryNo":18,"categoryName":19,"taxonomyType":20,"taxonomyTypeDesc":21},[122,129,130,49,104,105,45,109,131,132,133,134,135,136,137,115,138,139,140,141,28],"MCP","cli","Budget","credentials","team","catalog","use","call","discover","external tools","with","scoped","blob",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":96,"licenseFileUrl":146,"sourceHtmlUrl":147,"categories":148,"keywords":154,"publishedAt":52},"01M6WN93MEAZ4E41DYAHJRPHQT","recruit","Turn a job description into an evidence-linked candidate shortlist through Treg, with job-related ranking and optional authorized business contact enrichment.","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-recruit\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-recruit\u002FSKILL.md",[149],{"categoryNo":150,"categoryName":151,"taxonomyType":152,"taxonomyTypeDesc":153},"01JBSEEDCAT000000000000038","人力资源","PROFESSION","适用职业",[144,49,104,45,44,155,156,157,158,159,115,160,161,162,139,163,164,165,166,141,122,28],"email","enrichment","business","evidence","phone","ranking","post","job description","for","person","candidate","reason",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":96,"licenseFileUrl":171,"sourceHtmlUrl":172,"categories":173,"keywords":174,"publishedAt":52},"01M6WN8R5RXSMHM9B4D9FAFX42","rea-growth","Analyze a company’s public growth and content through Treg, distinguish observations from hypotheses, and produce an evidence-linked playbook within an approved budget.","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-rea-growth\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-rea-growth\u002FSKILL.md",[],[175,176,177,49,104,45,178,179,44,180,131,181,182,183,158,115,184,185,141,122,28],"growth","rea","rea growth","produce","content","playbook","marketing","analyze","public","observations","company",{"skillNo":187,"name":188,"nameZh":6,"description":189,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":96,"licenseFileUrl":190,"sourceHtmlUrl":191,"categories":192,"keywords":193,"publishedAt":52},"01M6WN2EVE3RQRGWAKBT4S7YT2","make-ugc","Create original AI UGC-style product videos through Treg: research hooks, approve a licensed presenter and voice, generate clips, add captions and report costs.","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-make-ugc\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-make-ugc\u002FSKILL.md",[],[194,195,49,196,104,197,45,198,199,200,201,202,115,203,204,205,206,207,208,141],"make","make ugc","research","create","Video","Captions","ads","short","hooks","head","style","niche","trending","talking-head","approve",{"skillNo":210,"name":211,"nameZh":6,"description":212,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":96,"licenseFileUrl":213,"sourceHtmlUrl":214,"categories":215,"keywords":216,"publishedAt":52},"01M6WN10ARAA63Y8K1YNGXJ2RM","lead-signals","Find and qualify public buying signals through Treg, rank fitting business accounts and optionally enrich authorized business contact information.","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-lead-signals\u002FLICENSE","https:\u002F\u002Fgithub.com\u002Fboisenoise\u002Fskills-collections\u002Fblob\u002Fmain\u002Fskills\u002Fantigravity-lead-signals\u002FSKILL.md",[],[217,218,219,49,104,45,220,221,157,222,223,115,224,225,226,227,228,229,230,141],"signals","lead","lead signals","how","find","ready","as","how to","qualify","people","information","enrich","changes","funding"]