Back to skill

Security audit

Cnpj Lookup

Security checks for vulnerabilities and agentic risk

Overview

This skill is a straightforward Brazilian CNPJ lookup tool that uses disclosed public APIs and local caching, with no evidence of hidden exfiltration, persistence, or privilege escalation.

Install only if you are comfortable sending CNPJ lookup targets to BrasilAPI, CNPJ.ws, and OpenCNPJ. Avoid using it for confidential investigations where the queried company identity or timing is sensitive, and use --no-cache for lookups you do not want retained locally in the skill cache.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/cnpj_lookup.py:169
Finding
Unbounded Recursive Retry on HTTP 429 Responses## Vulnerability Details **File Location**: `scripts/cnpj_lookup.py:169-175` **Vulnerability Type**: Unbounded recursive retry causing denial of service **Risk Level**: Medium ### Vulnerable Code ```python except urllib.error.HTTPError as e: if e.code == 429: retry_after = e.headers.get("Retry-After") wait = _rate_limiter.backoff(provider, int(retry_after) if retry_after else None) time.sleep(wait) # Tenta novamente uma vez return fetch_url(url, provider) ``` ### Technical Analysis When an API provider returns HTTP 429, `fetch_url()` waits and then calls itself recursively. No retry counter, recursion limit, or terminal condition restricts this behavior. Although the comment states that the request is retried once, the implementation retries indefinitely as long as the provider continues returning 429. Each retry retains another Python stack frame. A provider that persistently returns 429 can therefore keep the process sleeping and recursing until Python raises `RecursionError`. Because the function does not return `None` while this cycle continues, `fetch_with_fallback()` cannot proceed to the next provider. The `Retry-After` value is also converted directly with `int()`. An HTTP-date or malformed value can raise `ValueError`; however, the surrounding provider-level exception handler will generally catch that error and continue fallback, so the confirmed security concern is the unbounded recursive retry. ### Attack Path 1. A user initiates a CNPJ lookup. 2. The application sends a request to a configured provider. 3. The provider, or an intermediary controlling the response path, repeatedly returns HTTP 429. 4. Each response causes `fetch_url()` to sleep and invoke itself recursively. 5. The process remains blocked, fallback providers are not reached, and stack frames accumulate. 6. Continued responses eventually cause stack exhaustion and a `RecursionError`, ter ...[truncated 587 chars]
Remediation
## Remediation Suggestions Replace recursive retry with a bounded iterative loop: 1. Set an explicit maximum retry count, preferably one retry to match the documented behavior. 2. After the retry limit is reached, return `None` so `fetch_with_fallback()` can try the next provider. 3. Parse `Retry-After` defensively. Support both integer delay values and HTTP-date values, and reject malformed or unreasonable values. 4. Cap all wait periods to a documented maximum. 5. Log retry attempts and final provider failure without exposing sensitive response data. 6. Add tests for persistent 429 responses, malformed `Retry-After` headers, and successful fallback after retry exhaustion. Example hardened structure: ```python def fetch_url(url: str, provider: str, max_retries: int = 1) -> Optional[Dict]: for attempt in range(max_retries + 1): try: req = urllib.request.Request( url, headers={"User-Agent": "CNPJ-Lookup/1.0"} ) with urllib.request.urlopen(req, timeout=15) as response: return json.loads(response.read().decode("utf-8")) except urllib.error.HTTPError as e: if e.code != 429: print(f"HTTP Error {e.code}: {e.reason}", file=sys.stderr) return None if attempt >= max_retries: return None retry_after = e.headers.get("Retry-After") try: delay = int(retry_after) if retry_after else None except (TypeError, ValueError): delay = None time.sleep(_rate_limiter.backoff(provider, delay)) return None ```
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (10)

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The README explicitly states that CNPJ lookups are performed against public APIs, but it does not warn users that their query terms and associated metadata will be transmitted to third-party services. While CNPJ data is business-oriented and often public, user queries may still contain sensitive investigative context, internal targets, or personal contact data tied to a company search, creating a privacy and data-handling risk.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises script execution with network, cache, and file behaviors but does not declare any explicit tool scope or permissions boundaries. That makes the operational surface ambiguous and can lead to over-privileged execution or unintended access to filesystem, environment variables, or external endpoints when the skill is invoked.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The activation description is broad enough to trigger on generic requests about company details, searches, addresses, or registration data, which increases the chance of accidental invocation. In an agent setting, overly broad triggers can cause unexpected network calls, data handling, or execution of supporting scripts when the user did not clearly request this specific skill.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
This markdown file presents all instructions and schema notes exclusively in Portuguese, which can constitute a language-policy violation when the skill does not offer user opt-in or a language alternative. The document does not state that the skill is intentionally limited to Portuguese-speaking or Brazil-specific users as a documented exception.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill is explicitly designed to send user-supplied CNPJ queries to multiple third-party public APIs, but the provider documentation contains no user-facing disclosure, consent requirement, or privacy guidance about that external sharing. Even though CNPJ data is business-related and often public, user queries can still reveal investigative intent, associated entities, or linked context, and that metadata is exposed to external services during fallback and retry behavior.

External Transmission

Medium
Category
Data Exfiltration
Content
### Endpoint
```
GET https://api.opencnpj.org/{cnpj}
```
(Aceita CNPJ com ou sem pontuação)
Confidence
84% confidence
Finding
This endpoint confirms that the skill transmits lookup inputs to an external third-party service as part of its normal operation. In context, the danger is not code execution but data egress: user queries, timing, and lookup targets are disclosed to OpenCNPJ, and because it is part of an automatic fallback chain, this transmission may occur without the user realizing which provider receives the data.

External Transmission

Medium
Category
Data Exfiltration
Content
PROVIDERS = {
    "brasilapi": "https://brasilapi.com.br/api/cnpj/v1/{}",
    "cnpjws": "https://publica.cnpj.ws/cnpj/{}",
    "opencnpj": "https://api.opencnpj.org/{}"
}
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The skill stores lookup results in a local cache file without warning the user that company, contact, address, and QSA data may persist on disk. On shared systems or multi-user agent environments, this can create unintended retention and secondary disclosure of queried entities and returned data.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill sends the queried CNPJ to third-party public APIs as its core function, but it does so without any explicit user-facing disclosure or consent flow. Even though CNPJ data is generally public, user queries may still be sensitive in context (e.g., confidential investigations, prospecting targets, or internal due diligence), and transmitting them to external providers can leak business intent and query metadata.

Natural-Language Policy Violations

Low
Confidence
93% confidence
Finding
A linha contém 'Consulta simples (apenas基本信息)', inserindo texto em chinês em uma documentação predominantemente em português. Isso impõe um idioma adicional sem opt-in ou justificativa documentada, contrariando a política de escolha de idioma/locale para linguagem natural.

Static analysis

No suspicious patterns detected.