Back to skill

Security audit

AFOL Rebrickable

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its Rebrickable purpose, but it needs Review because credential handling is under-scoped and some write guidance is inconsistent.

Install only if you are comfortable giving the skill access to your Rebrickable API key and, for private actions, your user token. Do not set REBRICKABLE_BASE_URL or --base-url to anything except the official Rebrickable API, avoid passing --user-token on the command line, and require a dry run plus explicit confirmation before any create, update, or delete action.

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 (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/rebrickable_cli.py:42
Finding

Credentials Can Be Transmitted to an Arbitrary Network Destination

Content
View full analysis
dict[str, str]: headers = {"Accept": "application/json", "Authorization": f"key {self.api_key}"} if content_type: headers["Content-Type"] = content_type return headers def _url(self, path: str, params: dict[str, Any] | None = None) -> str: query = urllib.parse.urlencode(clean_params(params or {}), doseq=True) suffix = f"?{query}" if query else "" return f"{self.base_url}{path}{suffix}" def _request(self, method: str, url: str, body: bytes | None = None, headers: dict[str, str] | None = None) -> Any: request = urllib.request.Request(url, data=body, headers=headers or {}, method=method) try: with urllib.request.urlopen(request, timeout=self.timeout) as response: raw = response.read().decode("utf-8") ``` ```python def add_common(parser: argparse.ArgumentParser) -> None: parser.add_argument("--base-url", default=os.getenv("REBRICKABLE_BASE_URL", DEFAULT_BASE_URL), help="Rebrickable API base URL") parser.add_argument("--timeout", type=int, default=READ_TIMEOUT_SECONDS, help="HTTP timeout in seconds") ``` ```python def user_path(args: argparse.Namespace, suffix: str) -> str: token = "[from REBRICKABLE_USER_TOKEN]" if getattr(args, "dry_run", False) else quote(user_token(args)) return f"/users/{token}/{suffix.lstrip('/')}" ``` ### Technical Analysis The CLI accepts the ...[truncated 2275 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/rebrickable_cli.py:111
Finding

Private User Token Can Be Exposed Through Command-Line Arguments

Content
View full analysis
str: token = getattr(args, "user_token", None) or os.getenv("REBRICKABLE_USER_TOKEN") if not token: raise RebrickableCliError("provide --user-token or set REBRICKABLE_USER_TOKEN for user collection endpoints") return token ``` ```python def add_user_token(parser: argparse.ArgumentParser) -> None: parser.add_argument("--user-token", help="Rebrickable user token; defaults to REBRICKABLE_USER_TOKEN") ``` The Skill documentation also permits the flag: ```text User read-only examples, only when REBRICKABLE_USER_TOKEN is configured or passed with --user-token: ``` ### Technical Analysis Passing secrets through command-line arguments can expose them through shell history, process listings, terminal capture, audit telemetry, command transcripts, CI logs, and Agent conversation records. This behavior also contradicts the module-level security statement that secrets come from environment variables and never from flags. Redaction of dry-run output does not protect the original command line used to launch the process. ### Attack Path 1. A user or Agent runs a private command such as: ```bash scripts/rebrickable profile --user-token SECRET_TOKEN ``` 2. The command is retained in shell history, an Agent transcript, terminal logging, process monitoring, or execution telemetry. 3. A local user, administrator, monitoring service, or party with access to those records retrieves the token. 4. The token is combined with an API key and replayed against private Rebrickable endpoints. ### Impact Assessment The exposed token identifies the private user endpoint and may allow access to profile and collection information when co ...[truncated 309 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Note
Location
references/prompts/rebrickable-tools.txt:77
Finding

Mutation Guidance Can Bypass the Documented Confirmation Procedure

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (17)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- CLI source: `scripts/rebrickable_cli.py`

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
- CLI source: `scripts/rebrickable_cli.py`

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
User coverage:
- `GET /users/{user_token}/profile/`
- `GET/POST /users/{user_token}/setlists/`
- `GET/PATCH/DELETE /users/{user_token}/setlists/{list_id}/`
- `GET/POST /users/{user_token}/setlists/{list_id}/sets/`
- `GET/PATCH/DELETE /users/{user_token}/setlists/{list_id}/sets/{set_num}/`
- `GET /users/{user_token}/sets/`

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
- `GET/POST /users/{user_token}/setlists/`
- `GET/PATCH/DELETE /users/{user_token}/setlists/{list_id}/`
- `GET/POST /users/{user_token}/setlists/{list_id}/sets/`
- `GET/PATCH/DELETE /users/{user_token}/setlists/{list_id}/sets/{set_num}/`
- `GET /users/{user_token}/sets/`
- `GET /users/{user_token}/partlists/`
- `POST /users/{user_token}/partlists/`

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
- `GET /users/{user_token}/sets/`
- `GET /users/{user_token}/partlists/`
- `POST /users/{user_token}/partlists/`
- `DELETE /users/{user_token}/partlists/{list_id}/`
- `GET/POST /users/{user_token}/partlists/{list_id}/parts/`
- `PUT/DELETE /users/{user_token}/partlists/{list_id}/parts/{part_num}/{color_id}/`
- `GET /users/{user_token}/parts/`

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
- `POST /users/{user_token}/partlists/`
- `DELETE /users/{user_token}/partlists/{list_id}/`
- `GET/POST /users/{user_token}/partlists/{list_id}/parts/`
- `PUT/DELETE /users/{user_token}/partlists/{list_id}/parts/{part_num}/{color_id}/`
- `GET /users/{user_token}/parts/`
- `GET /users/{user_token}/allparts/`
- `GET /users/{user_token}/minifigs/`

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
80% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

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

md
- `GET /users/{user_token}/minifigs/`
- `GET /users/{user_token}/build/{set_num}/`
- `GET/POST /users/{user_token}/lost_parts/`
- `DELETE /users/{user_token}/lost_parts/{id}/`

Treat set-list names, part-list names, owned sets, part inventories, build analysis, lost parts, emails, and profile data as private. Summarize only what the user needs.

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The sync endpoint can replace a user's full set collection and explicitly deletes sets not present in the submitted list, which is materially more destructive than 'guarded collection writes.' In an agent-integrated environment, malformed prompts, model mistakes, or partial data submission could trigger irreversible bulk loss of user collection data.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding

The skill declares access to a networked API and relies on environment-provided credentials, but it does not define an explicit tool scope such as allowed-tools or permissions. That omission weakens policy enforcement and reviewability because an agent runtime may permit broader tool access than intended, increasing the chance of unintended secret access or outbound requests.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The OpenAPI surface exposes a username/password token-generation endpoint, which expands the skill from catalog lookup and guarded collection operations into direct credential handling. In an agent skill context, this is dangerous because it encourages the agent or its wrappers to collect, transmit, or process end-user credentials, increasing phishing, secret-handling, and accidental logging risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The /users/_token/ endpoint accepts username and password in form data to generate a user token, but the description only explains functionality and does not warn that it handles sensitive credentials. For a manifest file, this is a missing disclosure about privacy-sensitive behavior affecting account security.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

User authentication tokens are embedded in URL paths for user-specific endpoints, which makes them likely to appear in logs, traces, browser history, reverse proxies, and telemetry systems. Because these tokens authorize access to personal collection data and write actions, passive leakage can become account compromise or unauthorized data modification.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Although the description notes that the sync call will "completely replace" the user's sets and remove sets not found in the supplied list, it is not marked as a clear warning despite being an irreversible, destructive operation on user data. This file should provide a stronger user warning for such system-affecting behavior.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/prompts/rebrickable-tools.txt (reported line 67)May include surrounding context.

text
- Always confirm which service(s) were updated in your response

3. If ONLY ONE service is configured:
   - Use that service without asking
   - Still mention which service was used (e.g., "Added to your Rebrickable set list")

4. When user explicitly specifies the service (e.g., "add to Rebrickable"):

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · references/prompts/rebrickable-tools.txt (reported line 81)May include surrounding context.

text
- Always confirm which service(s) were updated in your response

3. If ONLY ONE service is configured:
   - Use that service without asking
   - Still mention which service was used (e.g., "Added to your Rebrickable set list")

4. When user explicitly specifies the service (e.g., "add to Rebrickable"):

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/rebrickable_cli.py (reported line 438)May include surrounding context.

python
def page_params(args: argparse.Namespace, *field_names: str) -> dict[str, Any]:
    params = {"page": args.page, "page_size": args.page_size, "ordering": args.ordering}
    params.update({field: getattr(args, field) for field in field_names})
    return params

Dynamic attribute access via getattr()

Low
Category
Dangerous Code Execution
Confidence
50% confidence
Finding

Dynamic getattr() with a non-literal attribute name can access arbitrary object attributes, potentially bypassing access controls.

Content

Scanner excerpt · scripts/rebrickable_cli.py (reported line 452)May include surrounding context.

python
def require_any(args: argparse.Namespace, field_names: Iterable[str]) -> None:
    if not any(getattr(args, field) is not None for field in field_names):
        raise RebrickableCliError("provide at least one field to update")

Static analysis

No suspicious patterns detected.