[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6NTHABCVFQC2Q549CQ565X3":3,"skill-same:01M6NTHABCVFQC2Q549CQ565X3":81},{"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":43,"linkOnly":44,"markdownContent":45,"markdownBody":46,"frontMatter":47,"refName":32,"commitSha":56,"skillDirectory":57,"forksCount":13,"repositoryHtmlUrl":58,"repositoryHomepageUrl":6,"ownerHtmlUrl":59,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":60,"install":61,"resources":74},"01M6NTHABCVFQC2Q549CQ565X3","ai-agent-security",null,"Secure AI agents against prompt injection, tool abuse, and data exfiltration with defense-in-depth controls.","duc-duy-1612\u002FOnline-Delivery-Systems-Web","duc-duy-1612","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F192231384?v=4","01M6NSDKQQDKVTHZ8DZMZ1VYY6","01M6NSDKW8DDVTQHBT1HBDDJPT",0,"MIT","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fai-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],"security","ai agent","ai agent security","agent security","defense","relevant","scripts","scope","active","main","community","only","devops-security","exfiltration","defense-in-depth","assessment","secure","ai agents","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\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 = risk in (RiskLevel.LOW, RiskLevel.MEDIUM)\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 result.risk_level == RiskLevel.CRITICAL:\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            if result.risk_level == RiskLevel.HIGH:\n                await log_security_event(\n                    event=\"input_flagged\",\n                    risk=result.risk_level.value,\n                    rules=result.matched_rules,\n                )\n                # Allow through but flag for review\n                kwargs[\"_security_flags\"] = result.matched_rules\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\nNever let an agent execute tools directly on the host. Isolate every tool invocation inside a sandbox.\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    cap_add:\n      - NET_BIND_SERVICE   # Only if tool needs network\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\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\ncat \u003C\u003C'EOF' | sudo tee \u002Fetc\u002Fdocker\u002Fdaemon.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 \\\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 Enforcement\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 in args and not isinstance(args[arg_name], expected_type):\n                return False\n\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\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 = risk in (RiskLevel.LOW, RiskLevel.MEDIUM)\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 result.risk_level == RiskLevel.CRITICAL:\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            if result.risk_level == RiskLevel.HIGH:\n                await log_security_event(\n                    event=\"input_flagged\",\n                    risk=result.risk_level.value,\n                    rules=result.matched_rules,\n                )\n                # Allow through but flag for review\n                kwargs[\"_security_flags\"] = result.matched_rules\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\nNever let an agent execute tools directly on the host. Isolate every tool invocation inside a sandbox.\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    cap_add:\n      - NET_BIND_SERVICE   # Only if tool needs network\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\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\ncat \u003C\u003C'EOF' | sudo tee \u002Fetc\u002Fdocker\u002Fdaemon.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 \\\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 Enforcement\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 in args and not isinstance(args[arg_name], expected_type):\n                return False\n\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":41,"source":48,"license":14,"category":23,"metadata":49,"date_added":52,"description":7,"source_repo":53,"source_type":33,"compatibility":54,"license_source":55},"https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills",{"author":50,"version":51},"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","f3312ba749561b6159f477dbfc9313c875d40a56",".agents\u002Fskills_archive\u002Fai-agent-security","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612","2026-10-25 23:50:58",{"source":8,"skillName":5,"commands":62,"prompt":72,"zipAvailable":73},[63,66,69],{"tool":64,"command":65},"npx","npx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill ai-agent-security",{"tool":67,"command":68},"bunx","bunx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill ai-agent-security",{"tool":70,"command":71},"pnpm","pnpm dlx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill ai-agent-security","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fai-agent-security\u002FSKILL.md",true,[75],{"path":76,"resourceType":77,"resourceTypeDesc":78,"sizeBytes":79,"sourceHtmlUrl":80},"references\u002Fdetails.md","REFERENCE","参考文档",29976,"https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fai-agent-security\u002Freferences\u002Fdetails.md",[82,102,126,150,178,202],{"skillNo":83,"name":84,"nameZh":6,"description":85,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":86,"categories":87,"keywords":91,"publishedAt":43},"01M6Q0FA5FZ410Z33Z3TFQ4DBA","zero-trust","Implement zero-trust network architecture. Configure identity-based access, micro-segmentation, and continuous verification. Use when implementing modern security architectures.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fzero-trust\u002FSKILL.md",[88],{"categoryNo":89,"categoryName":90,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000011","运维与部署",[92,93,94,95,38,96,84,97,35,98,99,34,33,32,31,100,30,29,28,101],"ZeRO","trust","zero trust","architecture","verification","segmentation","access","configure","critical","implementing",{"skillNo":103,"name":104,"nameZh":6,"description":105,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":106,"categories":107,"keywords":108,"publishedAt":43},"01M6Q0F1YZJW3KX5FBKEVZ8CV4","zcode-delegate","Delegate coding tasks to the Z.AI ZCode CLI only when the user explicitly requests it, while the orchestrator retains review and landing responsibility.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fzcode-delegate\u002FSKILL.md",[],[109,110,111,112,113,114,115,116,117,118,119,120,121,34,122,33,123,124,100,125],"delegate","zcode","zcode delegate","review","cli","orchestration","tasks","run","Bash","model","node","read","orchestrator","files","desktop app","app","agent-orchestration",{"skillNo":127,"name":128,"nameZh":6,"description":129,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":130,"categories":131,"keywords":132,"publishedAt":43},"01M6Q0ETK41VGNMYEXW0T00AJN","youtube-transcript","Fetch YouTube transcripts through DeepAPI or local fallback tooling and save clean text output.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-transcript\u002FSKILL.md",[],[133,134,135,41,136,137,138,139,140,141,142,143,144,33,32,145,146,147,148,149],"transcript","youtube transcript","youtube","github","codex","research","license","https","text","fetch","tooling","clean","local","output","deepapi","youtube transcripts","blob",{"skillNo":151,"name":152,"nameZh":6,"description":153,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":154,"categories":155,"keywords":167,"publishedAt":43},"01M6Q0EPPH2PVMDW40017F8WX0","youtube-transcript-skills","Fetch YouTube video transcripts, search videos\u002Fchannels, browse channels, and extract playlists via the getyoutubetranscript.com API - free tier, no card required.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-transcript-skills\u002FSKILL.md",[156,159,162],{"categoryNo":157,"categoryName":158,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":160,"categoryName":161,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":163,"categoryName":164,"taxonomyType":165,"taxonomyTypeDesc":166},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[133,134,135,168,41,169,136,137,139,170,171,172,173,142,174,33,32,175,176,177],"youtube transcript skills","gemini","search","api","Video","browse","api-integration","free","card","channels",{"skillNo":179,"name":180,"nameZh":6,"description":181,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":182,"categories":183,"keywords":188,"publishedAt":43},"01M6Q0EAB96PX83W5PTE8A0R8D","youtube-notetaker","Turn YouTube talks into local study notes with slides, transcripts, editable annotations, and a markdown-backed viewer.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-notetaker\u002FSKILL.md",[184,187],{"categoryNo":185,"categoryName":186,"taxonomyType":20,"taxonomyTypeDesc":21},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":160,"categoryName":161,"taxonomyType":20,"taxonomyTypeDesc":21},[135,189,190,113,41,191,192,193,194,139,172,195,196,197,198,32,199,145,200,201],"youtube notetaker","notetaker","workflow","official","notes","code","markdown","slides","annotations","README","study","dair-academy","viewer",{"skillNo":203,"name":204,"nameZh":6,"description":205,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":206,"categories":207,"keywords":209,"publishedAt":43},"01M6Q0E55F0GW5MX48V8HXS8B5","youtube-full","Fetch YouTube transcripts, search videos, browse channels, and extract playlists via TranscriptAPI — no yt-dlp, no Google API key, works from any cloud server.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-full\u002FSKILL.md",[208],{"categoryNo":157,"categoryName":158,"taxonomyType":20,"taxonomyTypeDesc":21},[210,135,211,212,41,169,170,213,214,171,172,173,142,215,174,33,32,175,216,148],"youtube full","full","google","server","dlp","credits","automatic"]