Back to skill

Security audit

Brikko PII Mask

Security checks for vulnerabilities and agentic risk

Overview

This is a coherent PII-masking skill, but it needs Review because sensitive data and an API key can be sent to a configurable network endpoint without adequate endpoint safeguards.

Install only if you are comfortable sending plaintext PII to Brikko or to a carefully controlled self-hosted endpoint. Do not set BRIKKO_API_URL to remote HTTP, restrict who can set that environment variable, and prefer a reviewed/pinned self-hosted deployment if regulated data cannot leave your environment.

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

Error
Location
scripts/mask.py:45
Finding

Custom API configuration permits transmission of PII and credentials over cleartext HTTP

Content
View full analysis
MAX_TEXT_BYTES: fail_config( f"Text exceeds {MAX_TEXT_BYTES} bytes. Split into chunks " "(e.g. by paragraph) and call mask.py per chunk." ) payload = json.dumps({"text": text}).encode("utf-8") req = urllib.request.Request( f"{api_url}/v1/anonymize", data=payload, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "User-Agent": "brikko-pii-skill/0.1.0", }, method="POST", ) ``` The same weakness is present in `scripts/restore.py`: ```python api_url = os.environ.get("BRIKKO_API_URL", DEFAULT_API_URL).rstrip("/") text = sys.stdin.read() if not text: fail_config("stdin is empty — pipe LLM response to restore.py") payload = json.dumps( {"text": text, "mapping_id": args.mapping_id} ).encode("utf-8") req = urllib.request.Request( f"{api_url}/v1/restore", data=payload, headers={ "Authorization": f"Bearer {api_key}", "Content-Type": "application/json", "User-Agent": "brikko-pii-skill/0.1.0", }, method="POST", ) ``` ### Technical Analysis The default endpoint is HTTPS, but the `BRIKKO_API_URL` environment variable is accepted without validating its scheme, hostname, or network destination. Consequently, the scripts permit an arbitrary remote `http://` endpoint. The masking request includes the original, unmasked stdin and a bearer API key. The data can contain names, passport details, tax identifier ...[truncated 2114 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:60
Finding

Optional self-hosting instructions install and execute an unpinned global npm package

Content
View full analysis
Remediation
View remediation
`. 2. Publish and document package integrity hashes or signed provenance that users can verify before installation. 3. Prefer a project-local installation with a committed lockfile rather than a global package. 4. Avoid combining installation and execution in one shell command. Make verification an explicit step between them. 5. Document the canonical npm namespace, publisher identity, repository, and expected package signature or provenance. 6. Audit and pin transitive dependencies used by the self-hosted tooling. 7. Advise users not to run npm or the initialization command with administrative privileges unless strictly necessary. 8. Consider distributing a versioned, signed container image or release artifact for the self-hosted service. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Output HandlingUnvalidated Output Injection, Cross-Context Output, Unbounded Output
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Unvalidated Output Injection

High
Category
Output Handling
Confidence
85% confidence
Finding

Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Content

Scanner excerpt · README.md (reported line 105)May include surrounding context.

md
# 3. Restore placeholders in response
    if r["mapping_id"]:
        response = subprocess.check_output(
            ["python3", "scripts/restore.py", "--mapping-id", r["mapping_id"]],
            input=response, text=True
        )

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

A second aspect of the same mismatch is that the file claims broad detection, inflection handling, checksum validation, and workflow guarantees without demonstrating those controls in the skill itself. In security-sensitive contexts, overstating capability can cause users to trust masking coverage that may be incomplete, resulting in accidental leakage of unmasked PII.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

A second aspect of the same mismatch is that the file claims broad detection, inflection handling, checksum validation, and workflow guarantees without demonstrating those controls in the skill itself. In security-sensitive contexts, overstating capability can cause users to trust masking coverage that may be incomplete, resulting in accidental leakage of unmasked PII.

Content

No source excerpt is available for this finding.

Unvalidated Output Injection

High
Category
Output Handling
Confidence
85% confidence
Finding

Model output is used without validation or sanitization. Unvalidated output injected into downstream contexts (SQL, shell, HTML) enables injection attacks and arbitrary code execution.

Content

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

text

```python
restored = subprocess.check_output(
    ["python3", "scripts/restore.py", "--mapping-id", result["mapping_id"]],
    input=llm_response, text=True
).strip()

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill description is written as specifically for Russian-business use and focuses exclusively on Russian identifiers and formats, with no indication that locale selection is optional. Under the policy rule, language/locale constraints should be offered as a choice or explicitly justified as region-specific; here the README strongly assumes an RF-only context without that explicit framing.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill requires environment secrets and clearly transmits user-supplied text to an external network service, but it declares no explicit tool scope or permission boundary. In an agent setting, that omission can cause users or orchestrators to treat the skill as less privileged than it really is, increasing the risk of unintended secret use or data exfiltration.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
98% confidence
Finding

The skill explicitly sends plaintext personal data to an external service at api.brikko.ru for processing and stores mapping data server-side for up to one hour. In a PII-protection skill, this is highly sensitive behavior: even if intended, it materially changes the trust boundary and can create compliance, confidentiality, and third-party exposure risks if users assume data stays local.

Content

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

md
## Конфигурация

Skill использует Brikko Gateway API (`https://api.brikko.ru/v1/anonymize`,
`/v1/restore`). Чтобы получить API-ключ:

1. Регистрация на [brikko.ru](https://brikko.ru) (бесплатно, 200 ₽

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Tainted flow: 'req' from sys.stdin.read (line 59, user input) → urllib.request.urlopen (network output)

Medium
Category
Data Flow
Confidence
91% confidence
Finding

The script reads arbitrary stdin content and sends it over the network to an external service for anonymization. In the context of a PII-masking skill, this is intentional functionality, but it still creates a real confidentiality boundary: sensitive user data leaves the local environment and is disclosed to a third party, with the destination partially controllable via BRIKKO_API_URL.

Content

Scanner excerpt · scripts/mask.py (reported line 73)May include surrounding context.

python
last_err = None
    for attempt in range(3):
        try:
            with urllib.request.urlopen(req, timeout=TIMEOUT_SECONDS) as resp:
                body = resp.read().decode("utf-8")
                result = json.loads(body)
                # Pass-through to stdout — caller (agent) parses this JSON.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This restore step sends the full LLM output plus mapping_id to an external service, and that output may contain sensitive placeholders or context tied to real identities. In the context of a privacy-preserving skill, shipping data to a third-party API is the core trust boundary, so lack of an explicit runtime warning/consent mechanism can cause unintended disclosure or policy noncompliance, especially in regulated environments.

Content

No source excerpt is available for this finding.

Tainted flow: 'req' from sys.stdin.read (line 61, user input) → urllib.request.urlopen (network output)

Medium
Category
Data Flow
Confidence
65% confidence
Finding

Data from a source is assigned to a variable that is later passed to a sink, creating a variable-mediated taint flow.

Content

Scanner excerpt · scripts/restore.py (reported line 75)May include surrounding context.

python
last_err = None
    for attempt in range(3):
        try:
            with urllib.request.urlopen(req, timeout=TIMEOUT_SECONDS) as resp:
                body = resp.read().decode("utf-8")
                result = json.loads(body)
                # Plain text to stdout — easier для downstream агента который

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
76% confidence
Finding

The operational instructions and usage conditions are written entirely in Russian, which can impose a locale/language constraint on users without any stated opt-in or alternative. Under the policy, language constraints should either offer user choice or be clearly documented as a justified region-specific limitation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
88% confidence
Finding

The inline comment includes Russian text ('для downstream агента который просто берёт результат и отдаёт юзеру') in an otherwise English-language file. This can violate language consistency expectations when the skill does not document or offer a language/locale choice.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.exposed_secret_literal

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
README.md:61