Back to skill

Security audit

Dns Records

Security checks for vulnerabilities and agentic risk

Overview

This DNS lookup skill is purpose-aligned and disclosed, with a real but limited input-validation weakness around the external dig command.

Install only if you are comfortable with the skill making DNS queries from your machine. Use normal domain names and the documented record types; the publisher should add allowlists for record types and domain validation to prevent dig option abuse.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T09 · Insecure Skill Coding Practices

Warning
Location
dnscheck.py:8
Finding

Unvalidated dig Arguments Permit Native Option Injection in the Root Script

Content
View full analysis

Vulnerability Details

File Location: dnscheck.py:8-11 (input originates at dnscheck.py:38-39)
Vulnerability Type: Native command argument injection
Risk Level: Medium

Vulnerable Code

python
def dig(domain, rtype="A"):
    """Use system dig if available, fall back to socket."""
    try:
        out = subprocess.run(
            ["dig", "+short", "+timeout=5", rtype, domain],
            capture_output=True, text=True, timeout=10
        )

The relevant command-line input is accepted without validation:

python
p.add_argument("domains", nargs="+", help="Domains to look up")
p.add_argument("-t", "--type", nargs="+", default=None, help="Record types (A, AAAA, MX, NS, TXT, CNAME, SOA)")

Technical Analysis

Both rtype and domain are controlled by command-line arguments and are passed directly to dig. The use of an argument list with shell=False prevents shell metacharacter injection, but it does not prevent native argument injection into the invoked program.

dig recognizes arguments beginning with characters such as -, +, and @ as control arguments. Consequently, a purported record type such as @attacker-controlled-resolver.example may be interpreted as a resolver selection directive rather than as a DNS record type. Other native options can modify query behavior or activate batch-file processing.

The advertised record types are documented but not enforced. No allowlist restricts rtype to A, AAAA, MX, NS, TXT, CNAME, and SOA, and domain values are not validated before reaching the process boundary.

Attack Path

  1. An attacker or untrusted caller supplies a crafted value through --type, such as a dig control argument beginning with @, +, or -.
  2. argparse stores the value without checking it against the documented record-type set.
  3. dig() inserts the value directly into the command argument list before the domain.

...[truncated 1038 chars]

Remediation
View remediation

Remediation Suggestions

  1. Enforce a case-insensitive allowlist before invoking dig:

    python
    ALLOWED_TYPES = {"A", "AAAA", "MX", "NS", "TXT", "CNAME", "SOA"}
    
    def validate_rtype(value):
        value = value.upper()
        if value not in ALLOWED_TYPES:
            raise argparse.ArgumentTypeError(f"Unsupported record type: {value}")
        return value
    

    Apply the validator through argparse:

    python
    p.add_argument(
        "-t", "--type",
        nargs="+",
        type=validate_rtype,
        default=None,
        help="Record types (A, AAAA, MX, NS, TXT, CNAME, SOA)"
    )
    
  2. Validate each domain as a DNS hostname or IP literal. Reject control prefixes such as -, +, and @, empty labels, invalid characters, and names exceeding DNS length limits.

  3. Construct the dig invocation so fixed query components are unambiguous. Do not rely solely on shell avoidance as protection against application-level option parsing.

  4. Add tests confirming that values such as @resolver, -f, +trace, and unsupported record types are rejected before subprocess.run is called.

  5. Keep the duplicate root and scripts/ implementations synchronized, or consolidate them into one implementation to prevent security fixes from being applied to only one copy.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/dnscheck.py:8
Finding

Unvalidated dig Arguments Permit Native Option Injection in the Skill Script

Content
View full analysis

Vulnerability Details

File Location: scripts/dnscheck.py:8-11 (input originates at scripts/dnscheck.py:38-39)
Vulnerability Type: Native command argument injection
Risk Level: Medium

Vulnerable Code

python
def dig(domain, rtype="A"):
    """Use system dig if available, fall back to socket."""
    try:
        out = subprocess.run(
            ["dig", "+short", "+timeout=5", rtype, domain],
            capture_output=True, text=True, timeout=10
        )

The relevant command-line input is accepted without validation:

python
p.add_argument("domains", nargs="+", help="Domains to look up")
p.add_argument("-t", "--type", nargs="+", default=None, help="Record types (A, AAAA, MX, NS, TXT, CNAME, SOA)")

Technical Analysis

User-controlled record types and domains are passed directly as arguments to the system dig utility. Although list-based subprocess.run usage prevents shell injection, it does not stop dig from interpreting attacker-controlled values as its own options or control syntax.

Values beginning with @, +, or - can have special meaning to dig. For example, an @ argument can select a different DNS server. The implementation documents a fixed list of supported record types but does not enforce that list, allowing an untrusted caller to change command semantics.

Attack Path

  1. An attacker invokes the skill script with a crafted --type value that is valid native syntax for dig.
  2. The parser accepts the value because no type validator or allowlist is configured.
  3. check_domain() passes the value to dig().
  4. dig() places it directly in the external process argument vector.
  5. dig interprets the value as a control argument, potentially redirecting queries or enabling unintended behavior.

The vulnerability does not directly permit arbitrary shell command execution. Its exploitation surface is constrained to dig options and the ...[truncated 561 chars]

Remediation
View remediation

Remediation Suggestions

  1. Normalize record types to uppercase and reject every value outside the explicit set A, AAAA, MX, NS, TXT, CNAME, and SOA.
  2. Validate domain arguments as hostnames or IP literals and reject values beginning with -, +, or @.
  3. Perform validation before entering check_domain() or invoking any external process.
  4. Add regression tests for @attacker-resolver, +trace, -f, malformed hostnames, and unsupported record types.
  5. Remove the duplicated implementation or centralize command construction and validation in a shared module so both entry points receive identical security fixes.
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill invokes shell-capable functionality (python3 scripts/dnscheck.py) and explicitly depends on the system dig command, but the manifest does not declare any tool scope such as permissions or allowed-tools. This weakens least-privilege controls and makes it harder for a host agent to constrain execution, increasing the risk of unintended command execution or abuse if the skill is invoked in a broader environment.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · dnscheck.py (reported line 8)May include surrounding context.

python
def dig(domain, rtype="A"):
    """Use system dig if available, fall back to socket."""
    try:
        out = subprocess.run(
            ["dig", "+short", "+timeout=5", rtype, domain],
            capture_output=True, text=True, timeout=10
        )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/dnscheck.py (reported line 8)May include surrounding context.

python
def dig(domain, rtype="A"):
    """Use system dig if available, fall back to socket."""
    try:
        out = subprocess.run(
            ["dig", "+short", "+timeout=5", rtype, domain],
            capture_output=True, text=True, timeout=10
        )