Back to skill

Security audit

Urban Sports Club Booking API

Security checks for vulnerabilities and agentic risk

Overview

This skill does what it says, but it asks for local account credentials and can make or cancel real bookings with weak safeguards and inconsistent credential-file packaging.

Review this carefully before installing. Do not put real account credentials in the packaged credentials.json or commit them to source control; prefer a secret manager or a protected file outside the project. Only run booking or cancellation commands when you intend to modify your Urban Sports Club account.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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

Warning
Location
credentials.json:1
Finding

Plaintext Credential Storage in a Project-Local JSON File

Content
View full analysis

Vulnerability Details

File Location: credentials.json:1-4
Related Locations: scan.py:77-93, SKILL.md:20-31
Vulnerability Type: Plaintext sensitive-data storage
Risk Level: Medium

Vulnerable Code

credentials.json:1-4:

json
{
  "email": "deine-email@beispiel.de",
  "password": "dein-passwort"
}

scan.py:77-93:

python
def load_credentials():
    """Laedt Zugangsdaten aus credentials.json."""
    creds_path = Path(__file__).parent / "credentials.json"
    if not creds_path.exists():
        print("Fehler: credentials.json nicht gefunden.", file=sys.stderr)
        print("Kopiere credentials.example.json -> credentials.json und trage deine Daten ein.", file=sys.stderr)
        return None

    with open(creds_path) as f:
        creds = json.load(f)

    if not creds.get("email") or not creds.get("password"):
        print("Fehler: email oder password in credentials.json ist leer.", file=sys.stderr)
        return None

    return creds

SKILL.md:20-31:

markdown
### 2. Zugangsdaten

Trage deine USC-Logindaten ein:

```json
{
  "email": "deine-email@beispiel.de",
  "password": "dein-passwort"
}

Die Datei credentials.json ist in .gitignore und wird nicht committet. Zugangsdaten werden nur fuer --book, --cancel und --bookings benoetigt.

text

### Technical Analysis

The application instructs users to place an account password in a plaintext JSON file located directly inside the project directory. The credential loader then reads this file without checking its ownership or permissions.

Although the audited file contains placeholder values rather than an exposed real password, it is intended to be overwritten with live credentials. The documentation claims that `credentials.json` is excluded through `.gitignore`, but no `.gitignore` file exists in the audited project directory. Moreover, because `credentials.json` is already present in the artifact, adding an ignore rule later would not protect it 
...[truncated 1699 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove credentials.json from the distributed project and version-control history.
  2. Distribute only a clearly non-secret template such as credentials.example.json.
  3. Add /credentials.json to a project-root .gitignore before users create the real file.
  4. If the file has previously been tracked, remove it from the index and purge any real credentials from repository history.
  5. Prefer an operating-system credential manager, secret-management service, or narrowly scoped environment variables over a project-local plaintext file.
  6. If file-based storage must remain:
    • Store the file outside the source tree.
    • Require owner-only permissions, such as mode 0600 on supported systems.
    • Validate ownership and permissions before reading it.
    • Refuse documented placeholder values.
  7. Add automated secret scanning and a test that fails if credentials.json is packaged or tracked.
  8. Rotate any real credentials that may already have been committed, uploaded, backed up, or shared.

T08 · Insecure Dependencies

Note
Location
SKILL.md:12
Finding

Unpinned Playwright and Browser Dependencies

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:12-14
Vulnerability Type: Unpinned third-party and browser dependencies
Risk Level: Low

Vulnerable Code

bash
venv/bin/pip install playwright
venv/bin/playwright install chromium
venv/bin/playwright install-deps chromium

Technical Analysis

The setup instructions install the latest version of the playwright Python package and dynamically retrieve the associated Chromium and system components. No exact package version, lock file, package hash, or fixed browser revision is declared by the project.

The package name is legitimate and the audit found no evidence of dependency confusion, typosquatting, or a currently malicious package. Nevertheless, resolving mutable dependencies at installation time means the installed code can differ from the code considered during this audit. A future compromised release, compromised distribution channel, or unexpected breaking update could therefore affect users without a project change.

The playwright install-deps chromium command may also invoke operating-system package management and require elevated privileges, depending on the host environment. This increases the potential impact of unsafe or unexpectedly changed installation behavior.

Attack Path

  1. A user follows the documented setup commands at a later date.
  2. The package manager resolves whatever Playwright release is current rather than a release reviewed with this project.
  3. Playwright retrieves browser artifacts, and install-deps may install additional system packages.
  4. If an upstream release, artifact, mirror, account, or distribution channel has been compromised, attacker-controlled installation or runtime code executes in the user's environment.
  5. Execution occurs with the privileges used for installation; system dependency installation may have elevated privileges if the user authorizes them.

This is a supply-chain hardening deficiency rather than evidence that the ...[truncated 632 chars]

Remediation
View remediation

Remediation Suggestions

  1. Pin Playwright to an explicitly reviewed version, for example through an exact requirements.txt entry rather than an unconstrained installation command.
  2. Generate and commit a dependency lock file containing cryptographic hashes for Python distributions.
  3. Document and pin the corresponding Playwright browser revision.
  4. Retrieve packages and browser artifacts only from authenticated, trusted repositories.
  5. Use a prebuilt, versioned container image or explicitly reviewed operating-system dependency list instead of running mutable privileged dependency-installation commands.
  6. Run installation without administrative privileges wherever possible and isolate browser execution in a minimally privileged environment.
  7. Automate dependency vulnerability scanning and review updates before changing pinned versions.
  8. Record dependency versions in release artifacts so installations remain reproducible and auditable.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (14)

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.

}

text

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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 123)May include surrounding context.

}

text

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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 134)May include surrounding context.

}

text

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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 135)May include surrounding context.

}

text

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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

python
}
```

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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

python
}
```

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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

python
}
```

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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

python
}
```

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

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

python
}
```

Die Datei `credentials.json` ist in `.gitignore` und wird nicht committet.
Zugangsdaten werden nur fuer `--book`, `--cancel` und `--bookings` benoetigt.

### 3. Venues konfigurieren

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The skill asks users to place account credentials in a local JSON file for automated login, but it does not include a clear privacy and security warning about how those credentials are used, stored, and protected. This can lead users to provide sensitive credentials without understanding the risks of local plaintext storage or browser automation-based login.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation exposes booking and cancellation commands that change the user’s Urban Sports Club account state, but it does not clearly warn that invoking these commands performs real account modifications. In an agent/automation context, lack of an explicit state-changing warning increases the risk of accidental bookings or cancellations triggered without informed user consent.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The module docstring materially understates the skill's capabilities by claiming it only scans studios and returns classes, while the code also authenticates with user credentials, reads bookings, books classes, and cancels them. This deception is dangerous in an agent-skill context because users or orchestrators may grant it trust or permissions appropriate for read-only scanning while it actually performs account actions.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The natural-language instructions throughout the file are German-only, which can amount to a language/locale policy issue when no user choice or explicit locale limitation is provided. The policy allows such constraints only when the skill offers opt-in language selection or clearly documents and justifies the locale restriction.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
96% confidence
Finding

The docstring instructs users in German ('Trage hier deine Venues ein', 'Die Venue-ID findest du...') and does not indicate that German is optional or required for a region-specific reason. This can violate a language/locale policy when users are not given an explicit choice or opt-in.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.