Back to skill

Security audit

Credential Scanner

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent secret-scanning skill, but its report output can expose the secrets it claims to mask and it can follow symlinks outside the requested scan folder.

Install only if you are comfortable treating all scanner output, especially JSON and saved reports, as sensitive. Avoid running it on untrusted repositories until symlink handling is fixed, and do not publish or upload generated reports without manually checking them for raw secrets.

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)

T09 · Insecure Skill Coding Practices

Error
Location
secret_scanner.py:524
Finding

JSON Reports Expose Unredacted Source Lines Containing Secrets

Content
View full analysis

Vulnerability Details

File Location: secret_scanner.py, lines 524–531 and 625
Vulnerability Type: Sensitive information disclosure through incomplete output redaction
Risk Level: High

Vulnerable Code

python
# Mask the secret for display
masked = mask_secret(matched_text)
line_preview = line.strip()[:120]

finding = SecretFinding(
    pattern_name=pattern_def["name"],
    severity=pattern_def["severity"],
    file_path=rel_path,
    line_number=i,
    line_preview=line_preview,
python
'findings': [asdict(f) for f in report.findings],

Technical Analysis

The scanner masks matched_text before assigning it to secret_preview, but separately stores the first 120 characters of the original source line in line_preview. This source line is not redacted.

The JSON formatter serializes the entire SecretFinding object using asdict(f). Consequently, line_preview is included in JSON output and can contain the complete secret. For example, if an API key appears near the beginning of a line, both a masked secret_preview and an unmasked line_preview will be emitted.

This behavior contradicts the documented claim that secret masking makes reports safe to share. The Markdown formatter does not currently print line_preview, but JSON output generated with --json or --json --output exposes it.

Attack Path

  1. A scanned source or configuration file contains a credential within the first 120 characters of a line.
  2. A user or CI job invokes the scanner with --json.
  3. The scanner detects the credential and masks the regex match for secret_preview.
  4. The scanner also stores the original, unredacted source line in line_preview.
  5. asdict(f) serializes that field into the JSON report.
  6. The report is printed to CI logs, retained as an artifact, or shared with another party.
  7. Anyone with access to that output can recover the exposed credential.

...[truncated 554 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not store an unredacted source line in SecretFinding.
  • Redact every regex match from the source line before assigning line_preview.
  • Prefer constructing an explicit JSON object rather than serializing every dataclass field with asdict().
  • Exclude line_preview from all externally visible output unless it has been safely sanitized.
  • Consider replacing the entire value portion of credential assignments rather than only the exact regex match.
  • Add regression tests that place known sentinel secrets at different positions in a line and assert that the raw values never occur in Markdown, JSON, standard output, or saved report files.
  • Treat existing JSON reports as potentially sensitive and remove them from public logs or artifacts where appropriate.

A safer implementation would redact matches before storing the preview:

python
redacted_line = line
for compiled in self._compiled_patterns:
    redacted_line = compiled["_regex"].sub("[REDACTED]", redacted_line)

line_preview = redacted_line.strip()[:120]

The JSON formatter should also explicitly select safe fields instead of serializing the complete dataclass.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
secret_scanner.py:479
Finding

Symbolic Links Permit File Reads Outside the Requested Scan Directory

Content
View full analysis

Vulnerability Details

File Location: secret_scanner.py, lines 479–493
Vulnerability Type: Scan-root boundary bypass through symbolic-link traversal
Risk Level: Medium

Vulnerable Code

python
if self.scan_path.is_file():
    self._scan_file(self.scan_path)
else:
    for file_path in sorted(self.scan_path.rglob('*')):
        if file_path.is_file():
            if should_scan_file(file_path):
                self._scan_file(file_path)
            else:
                self.report.files_skipped += 1
python
def _scan_file(self, file_path: Path):
    """Scan a single file for secrets."""
    try:
        content = file_path.read_text(encoding='utf-8', errors='ignore')

Technical Analysis

Directory traversal uses Path.rglob() and accepts entries for which file_path.is_file() returns true. For a symbolic link targeting a regular file, is_file() follows the link and returns true. The subsequent read_text() operation also follows the link.

The scanner does not reject symbolic links and does not resolve each candidate path and verify that the resulting target remains inside the resolved scan root. Therefore, an attacker-controlled project can include an eligible symbolic link, such as .env, that points to a readable file outside the project.

Extension and filename filtering does not provide a security boundary because eligibility is evaluated using the link's path and filename rather than the resolved target's location.

Attack Path

  1. An attacker prepares a repository or directory containing a symbolic link with a scanned filename or extension, such as .env.
  2. The symbolic link targets a file outside the repository that is expected to be readable in the victim environment.
  3. A victim or automated agent scans the attacker-controlled directory.
  4. rglob() discovers the link, and is_file() accepts it because its target is a regular file.
  5. `shoul ...[truncated 932 chars]
Remediation
View remediation

Remediation Suggestions

  • Reject symbolic links before examining or reading candidate files:
python
if file_path.is_symlink():
    self.report.files_skipped += 1
    continue
  • Resolve every candidate and verify containment within the resolved scan root:
python
root = self.scan_path.resolve()
candidate = file_path.resolve(strict=True)

try:
    candidate.relative_to(root)
except ValueError:
    self.report.files_skipped += 1
    return
  • Perform the containment check immediately before opening the file to reduce time-of-check/time-of-use risk.
  • If supported by the target platform, open files using mechanisms that reject symbolic links, such as O_NOFOLLOW, and validate the opened file descriptor.
  • Apply the same policy when the initial CLI path is itself a symbolic link, or explicitly document that behavior if following it is intentional.
  • Add tests covering file symlinks, directory symlinks, broken links, links pointing within the root, and links pointing outside the root.
  • Combine this correction with output redaction so that an unexpected read cannot disclose raw file content through reports.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (16)

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · SKILL.md (reported line 28)May include surrounding context.

md
- AWS Access Keys, Secret Keys, Session Tokens
  - Azure Storage Keys, Connection Strings, SAS Tokens
  - GCP Service Account Keys, API Keys
  - GitHub / GitLab / Bitbucket Personal Access Tokens
  - OpenAI, Anthropic, Hugging Face API Keys
  - Slack Bot Tokens, Webhooks
  - Stripe, Twilio, SendGrid Keys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 194)May include surrounding context.

python
- AWS Access Keys, Secret Keys, Session Tokens
  - Azure Storage Keys, Connection Strings, SAS Tokens
  - GCP Service Account Keys, API Keys
  - GitHub / GitLab / Bitbucket Personal Access Tokens
  - OpenAI, Anthropic, Hugging Face API Keys
  - Slack Bot Tokens, Webhooks
  - Stripe, Twilio, SendGrid Keys

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 366)May include surrounding context.

python
- AWS Access Keys, Secret Keys, Session Tokens
  - Azure Storage Keys, Connection Strings, SAS Tokens
  - GCP Service Account Keys, API Keys
  - GitHub / GitLab / Bitbucket Personal Access Tokens
  - OpenAI, Anthropic, Hugging Face API Keys
  - Slack Bot Tokens, Webhooks
  - Stripe, Twilio, SendGrid Keys

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 · secret_scanner.py (reported line 38)May include surrounding context.

python
'.py', '.js', '.ts', '.jsx', '.tsx', '.java', '.go', '.rb', '.php',
    '.cs', '.rs', '.c', '.cpp', '.h', '.swift', '.kt',
    '.json', '.yaml', '.yml', '.toml', '.ini', '.cfg', '.conf', '.xml',
    '.env', '.sh', '.bash', '.zsh', '.ps1', '.bat', '.cmd',
    '.md', '.txt', '.rst', '.properties',
}

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 · secret_scanner.py (reported line 44)May include surrounding context.

python
'.py', '.js', '.ts', '.jsx', '.tsx', '.java', '.go', '.rb', '.php',
    '.cs', '.rs', '.c', '.cpp', '.h', '.swift', '.kt',
    '.json', '.yaml', '.yml', '.toml', '.ini', '.cfg', '.conf', '.xml',
    '.env', '.sh', '.bash', '.zsh', '.ps1', '.bat', '.cmd',
    '.md', '.txt', '.rst', '.properties',
}

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 · secret_scanner.py (reported line 44)May include surrounding context.

python
SCAN_FILENAMES = {
    'Dockerfile', 'docker-compose.yml', 'docker-compose.yaml',
    'Makefile', '.env', '.env.local', '.env.development', '.env.production',
    '.env.staging', '.env.test', '.npmrc', '.pypirc', 'credentials',
    'config', '.htpasswd', 'wp-config.php',
}

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 · secret_scanner.py (reported line 44)May include surrounding context.

python
SCAN_FILENAMES = {
    'Dockerfile', 'docker-compose.yml', 'docker-compose.yaml',
    'Makefile', '.env', '.env.local', '.env.development', '.env.production',
    '.env.staging', '.env.test', '.npmrc', '.pypirc', 'credentials',
    'config', '.htpasswd', 'wp-config.php',
}

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 · secret_scanner.py (reported line 44)May include surrounding context.

python
SCAN_FILENAMES = {
    'Dockerfile', 'docker-compose.yml', 'docker-compose.yaml',
    'Makefile', '.env', '.env.local', '.env.development', '.env.production',
    '.env.staging', '.env.test', '.npmrc', '.pypirc', 'credentials',
    'config', '.htpasswd', 'wp-config.php',
}

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 45)May include surrounding context.

python
SCAN_FILENAMES = {
    'Dockerfile', 'docker-compose.yml', 'docker-compose.yaml',
    'Makefile', '.env', '.env.local', '.env.development', '.env.production',
    '.env.staging', '.env.test', '.npmrc', '.pypirc', 'credentials',
    'config', '.htpasswd', 'wp-config.php',
}

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 168)May include surrounding context.

python
},
    # --- GitHub ---
    {
        "name": "GitHub Personal Access Token",
        "pattern": r"(?<![A-Za-z0-9])(ghp_[A-Za-z0-9]{36,})(?![A-Za-z0-9])",
        "severity": "critical",
        "description": "GitHub Personal Access Token detected",

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 171)May include surrounding context.

python
},
    # --- GitHub ---
    {
        "name": "GitHub Personal Access Token",
        "pattern": r"(?<![A-Za-z0-9])(ghp_[A-Za-z0-9]{36,})(?![A-Za-z0-9])",
        "severity": "critical",
        "description": "GitHub Personal Access Token detected",

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 178)May include surrounding context.

python
},
    # --- GitHub ---
    {
        "name": "GitHub Personal Access Token",
        "pattern": r"(?<![A-Za-z0-9])(ghp_[A-Za-z0-9]{36,})(?![A-Za-z0-9])",
        "severity": "critical",
        "description": "GitHub Personal Access Token detected",

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 190)May include surrounding context.

python
},
    # --- GitHub ---
    {
        "name": "GitHub Personal Access Token",
        "pattern": r"(?<![A-Za-z0-9])(ghp_[A-Za-z0-9]{36,})(?![A-Za-z0-9])",
        "severity": "critical",
        "description": "GitHub Personal Access Token detected",

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · secret_scanner.py (reported line 193)May include surrounding context.

python
},
    # --- GitHub ---
    {
        "name": "GitHub Personal Access Token",
        "pattern": r"(?<![A-Za-z0-9])(ghp_[A-Za-z0-9]{36,})(?![A-Za-z0-9])",
        "severity": "critical",
        "description": "GitHub Personal Access Token detected",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
85% confidence
Finding

The skill describes and encourages scanning arbitrary files/directories and producing reports, which implies file read and possible file write behavior, but it does not declare any tool scope such as permissions or allowed-tools. In an agent ecosystem, undeclared capabilities reduce transparency and policy enforcement, increasing the risk of over-broad filesystem access or unintended data exposure when the skill is invoked.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
85% confidence
Finding

The scanner reads potentially sensitive files and prints report output containing file paths, line previews, and partially masked secret material to stdout or to a user-specified file. In a CI, shared terminal, or artifact-upload context, this can disclose repository-sensitive content beyond the minimum needed and create secondary leakage of secrets or confidential code fragments.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.