Back to skill

Security audit

Emissor de Nota Fiscal Paulistana

Security checks for vulnerabilities and agentic risk

Overview

This NFS-e skill mostly matches its invoicing purpose, but it handles certificate-backed tax actions with under-scoped email disclosure, plaintext retained data, and unsafe XML construction.

Review this skill carefully before installing. It can issue and cancel real São Paulo service invoices using your certificate, store client and fiscal records locally, and send invoice links by email. Only use it with non-production data until XML escaping, response logging, secret storage, and explicit confirmation for every email and production action are fixed.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
emitir_nfse.py:285
Finding
Unsigned user input is interpolated into XML before privileged signing and transmission<![CDATA[ ## Vulnerability Details **File Location**: `emitir_nfse.py:285-342`; related patterns also occur in `cancelar_nfse.py:47-62` and `baixar_notas.py:58-73` **Vulnerability Type**: XML injection through string interpolation **Risk Level**: High ### Vulnerable Code ```python xml_template = f"""<PedidoEnvioLoteRPS xmlns="http://www.prefeitura.sp.gov.br/nfe" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Cabecalho xmlns="" Versao="1"> <CPFCNPJRemetente> <CNPJ>{config['cnpj_prestador']}</CNPJ> </CPFCNPJRemetente> <transacao>false</transacao> <dtInicio>{nota['data_emissao']}</dtInicio> <dtFim>{nota['data_emissao']}</dtFim> <QtdRPS>1</QtdRPS> <ValorTotalServicos>{formata_valor(nota['valor_servicos'])}</ValorTotalServicos> <ValorTotalDeducoes>{formata_valor(nota.get('valor_deducoes', 0))}</ValorTotalDeducoes> </Cabecalho> <RPS xmlns=""> <Assinatura>{assinatura_rps}</Assinatura> <ChaveRPS> <InscricaoPrestador>{config['inscricao_municipal']}</InscricaoPrestador> <SerieRPS>{config['serie_rps']}</SerieRPS> <NumeroRPS>{nota['numero_rps']}</NumeroRPS> </ChaveRPS> <TipoRPS>RPS</TipoRPS> <DataEmissao>{nota['data_emissao']}</DataEmissao> <StatusRPS>{nota['status_rps']}</StatusRPS> <TributacaoRPS>{config['tributacao_rps']}</TributacaoRPS> <ValorServicos>{formata_valor(nota['valor_servicos'])}</ValorServicos> <ValorDeducoes>{formata_valor(nota.get('valor_deducoes', 0))}</ValorDeducoes> {f"<ValorPIS>{formata_valor(v_pis)}</ValorPIS>" if v_pis > 0 else ""} {f"<ValorCOFINS>{formata_valor(v_cofins)}</ValorCOFINS>" if v_cofins > 0 else ""} {f"<ValorINSS>{formata_valor(v_inss)}</ValorINSS>" if v_inss > ...[truncated 4112 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace string-built XML with `lxml.etree.Element` and `lxml.etree.SubElement`. - Assign untrusted values only through each element's `.text` property so the XML library performs escaping. - Apply strict allow-list validation before signing: - Invoice and RPS numbers: digits only with documented length limits. - Dates: valid ISO dates within an authorized range. - Status and retention indicators: fixed enumerations. - CNPJ and CPF fields: digits only with expected lengths and checksum validation. - State: two uppercase letters from the supported set. - Municipality and service codes: digits only with fixed limits. - Email: validated address format without control characters. - Monetary values: bounded, non-negative decimal values. - Validate the completed XML against the official municipal XSD before signing. - Present a canonical summary of security-sensitive fields to the user immediately before a production signature is created. - Apply the same element-builder and validation approach to issuance, cancellation, consultation, and reporting scripts. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
emitir_nfse.py:456
Finding
Production SOAP responses are retained in predictable plaintext files<![CDATA[ ## Vulnerability Details **File Location**: `emitir_nfse.py:456-457`; related response persistence occurs in `cancelar_nfse.py:141-142` and `consulta_rps.py:105-106` **Vulnerability Type**: Plaintext sensitive-data retention and unsafe predictable output files **Risk Level**: Medium ### Vulnerable Code ```python with open('debug_resposta_prod.xml', 'w', encoding='utf-8') as f: f.write(response.text) ``` ```python with open('debug_cancelamento.xml', 'w', encoding='utf-8') as f: f.write(response.text) ``` ```python with open("resposta_consulta.xml", "w") as f: f.write(response.text) ``` ### Technical Analysis Every relevant API response is written to a fixed filename in the current working directory. This occurs unconditionally, including during production operations. Municipal SOAP responses can contain invoice numbers, taxpayer identifiers, customer information, verification codes, processing errors, and other accounting metadata. The files are not created with an explicit restrictive mode, are not redacted, and are not deleted after use. Predictable filenames also create a local symlink risk when the working directory is writable by another user or process: an attacker could pre-create a symbolic link and cause the process to overwrite another file accessible to the executing account. ### Attack Path 1. The user issues, cancels, or queries invoices. 2. The script receives a production SOAP response containing fiscal information. 3. The complete response is written to a predictable plaintext file. 4. A local user, backup process, synchronization service, or later Skill execution accesses the retained response. 5. Alternatively, an attacker pre-creates the predictable filename as a symbolic link. 6. The script follows the link and overwrites the linked destination with the SOAP response. ### Impact Assessment The primary impact is unauthorized local disclosure and retention of fiscal and customer information. The exposed scope is ...[truncated 267 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove unconditional response logging from production code. - Enable diagnostic persistence only through an explicit debug option that defaults to disabled. - Redact taxpayer identifiers, customer records, verification codes, and other sensitive fields before logging. - If a diagnostic file is necessary, create it securely with a random filename and permissions equivalent to `0600`. - Use exclusive creation and reject symbolic links rather than opening predictable paths with ordinary write mode. - Store diagnostics in an application-controlled directory that is not shared with untrusted users. - Define a short retention period and delete diagnostic files automatically. - Log only status codes and sanitized municipal error identifiers during normal operation. ]]>

T01 · Skill Instruction Hijacking

Warning
Location
SKILL.md:53
Finding
The Skill mandates an additional email disclosure without transaction-specific consent<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:53` **Vulnerability Type**: Autonomous cross-Skill invocation and external transmission **Risk Level**: Medium ### Vulnerable Instruction ```text Mandatory autonomous action: invoke the GOG email-management Skill and send the invoice PDF link to your own email. ``` ### Technical Analysis After invoice issuance, the Skill instructs the agent to invoke a separate email-management Skill automatically. This behavior is mandatory even when the user's request is limited to issuing an invoice. The project does not define the recipient represented by “your own email,” does not document the separate Skill's implementation, and does not require the agent to display or confirm the destination before transmission. The PDF URL contains invoice-identifying and verification parameters. Transmitting it through an additional channel expands the data exposure beyond the municipal endpoint and the current user session. Email delivery is not necessary for the core declared function of issuing the invoice and returning its result to the user. ### Attack Path 1. The user requests and approves an invoice issuance. 2. The issuance script returns the official invoice number and PDF URL. 3. The loaded Skill instruction forces the agent to invoke the external GOG Skill. 4. The agent sends the URL to an unspecified or implicitly configured email destination. 5. The recipient, mailbox provider, email integration, or compromised external Skill obtains the invoice URL without explicit transaction-specific authorization from the user. ### Impact Assessment The instruction does not directly grant operating-system privileges. It exceeds least-necessary data-handling privileges by authorizing an additional external transmission and cross-Skill invocation. The affected scope includes invoice URLs and associated identifying or verification parameters. Depending on the external email Skill and mailbox configuration, disclosure ...[truncated 75 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Make email delivery optional rather than mandatory. - Require explicit user authorization immediately before invoking the email Skill. - Display the complete recipient address and a summary of the data that will be transmitted. - Do not infer a recipient from “your own email.” - Return the invoice result in the current session by default, which is sufficient for the core issuance workflow. - Invoke an external email integration only when the user expressly requests delivery. - Apply destination allow-listing and prevent automatic forwarding to newly supplied addresses without confirmation. - Minimize transmitted data and avoid including additional taxpayer or customer information when the official URL alone is sufficient. - Document the trust boundary and security behavior of any external Skill before integrating it. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (41)

Tainted flow: 'xml_consulta' from os.environ.get (line 95, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
temp_cert_path = temp_cert.name

    try:
        response = requests.post(
            url,
            data=xml_consulta.encode('utf-8'),
            headers=headers,
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'envelope_soap' from os.environ.get (line 80, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
try:
        print("Consultando API da prefeitura...")
        response = requests.post(url, data=envelope_soap.encode('utf-8'), headers=headers, cert=temp_cert_path, timeout=30)
        print("Status code:", response.status_code)
        
        with open("resposta_consulta.xml", "w") as f:
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tainted flow: 'envelope_soap' from os.environ.get (line 422, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
temp_cert_path = temp_cert.name

    try:
        response = requests.post(
            url,
            data=envelope_soap.encode('utf-8'),
            headers=headers,
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Missing User Warnings

High
Confidence
97% confidence
Finding
The README instructs users to provide sensitive organizational identifiers such as CNPJ and municipal registration directly in chat, but provides no clear privacy notice, retention policy, or warning about exposure in logs/history. In an invoicing skill, those identifiers are operationally sensitive and their casual collection through chat increases the risk of leakage, misuse, and unintended storage.

Ssd 3

High
Confidence
98% confidence
Finding
The statement that the AI will 'read hidden restrictions and passwords' and then return results in chat normalizes secret access by the model and suggests passwords are part of ordinary conversational processing. That is dangerous because it trains users to expect and accept secret retrieval through the assistant, increasing the chance of credential exposure, overbroad secret access, and unsafe agent behavior.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill claims issuance/cancellation, but the described ecosystem also includes consultation/querying of issued NFS-e records and local output of retrieved data. Undisclosed query and storage behavior can expose historical invoice data and creates a broader confidentiality risk than users may expect from the stated purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill claims issuance/cancellation, but the described ecosystem also includes consultation/querying of issued NFS-e records and local output of retrieved data. Undisclosed query and storage behavior can expose historical invoice data and creates a broader confidentiality risk than users may expect from the stated purpose.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill claims issuance/cancellation, but the described ecosystem also includes consultation/querying of issued NFS-e records and local output of retrieved data. Undisclosed query and storage behavior can expose historical invoice data and creates a broader confidentiality risk than users may expect from the stated purpose.

Ssd 3

High
Confidence
99% confidence
Finding
The setup flow instructs the agent to facilitate storing the certificate password in a local .env file as part of a chat-driven process. Handling certificate secrets in this way is highly sensitive: it normalizes plaintext local secret storage, risks accidental disclosure through tooling or repository sync, and ties a production financial credential to a loosely controlled workflow.

Missing User Warnings

High
Confidence
93% confidence
Finding
The code writes the private key and certificate to a temporary PEM file on disk, increasing exposure of highly sensitive key material. Even though the file is later deleted, the key may be accessible to other local processes depending on host configuration, may persist in backups or forensic artifacts, and will remain on disk if the process crashes before cleanup.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest description limits the skill to issuance and cancellation of NFS-e in São Paulo, but the public webservice interface also exposes multiple consultation operations, including lote status, lote contents, NFS-e by RPS, direct NFS-e lookup, and service-prestado/service-tomado queries. Those are materially broader business capabilities than mere emissão e cancelamento, not just internal implementation details.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The configuration turns on ConsultarSituacao, ConsultarLote, ConsultarRps, ConsultarNfse, ConsultarServicoPrestado, and ConsultarServicoTomado in addition to sending and canceling invoices. This confirms the skill's intended runtime behavior includes retrieval and reporting functions that exceed the manifest's narrower description.

Missing User Warnings

Medium
Confidence
82% confidence
Finding
The code saves generated RPS XML locally via SalvarXmlRps, and later persists returned NFSe XML via SalvarXmlNfse in several handlers, which can store sensitive fiscal and identity data on disk. There is no visible user-facing notice, confirmation, or explanatory comment in this file indicating that invoice documents will be written to local storage.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
This code constructs and submits a cancellation request for an NFSe, which is a potentially irreversible business action. Although the code includes technical comments about transaction batching semantics, it does not provide any user-facing confirmation or disclosure warning that a fiscal document cancellation will be executed.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
This code sends XML payloads containing invoice, CNPJ/CPF, municipal registration, and related fiscal data to remote prefeitura webservice endpoints across multiple methods. The file contains no user-facing confirmation, logging/print disclosure, or explanatory comments warning that sensitive fiscal data will be transmitted over the network.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The entire skill documentation and all example interactions are written as if the user must operate in Portuguese, with no mention of language options or opt-in. Under the stated policy, forcing a specific language without user choice is a natural-language policy concern unless the locale restriction is explicitly documented and justified.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The README expands the skill from invoice issuance/cancellation into an onboarding workflow that collects business identifiers in chat and writes configuration 'behind the scenes'. That is a meaningful scope expansion because users may invoke an invoicing skill without realizing it will gather and persist sensitive setup data, increasing privacy and consent risk.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger phrases are broad, natural-language prompts like 'Emita uma Nota' or 'Preciso testar a skill', which can cause accidental invocation during ordinary conversation. In a financial/government-service context, unintended activation can lead to collection of sensitive data or initiation of invoice-related actions without clear user intent.

Ssd 3

Medium
Confidence
95% confidence
Finding
Telling users to submit sensitive organizational identifiers directly in chat normalizes use of the conversational channel for secret or regulated setup data. Chat systems commonly retain history, logs, and transcripts, so this creates avoidable exposure of business identifiers during onboarding.

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill documents capabilities to read environment variables, read and write local files, and access external services, but it declares no explicit tool scope or permission boundaries. In a financial workflow that touches certificate material, customer records, and outbound email/reporting, this lack of scoping materially increases the risk of unintended data access, silent file modification, and exfiltration.

Vague Triggers

Medium
Confidence
92% confidence
Finding
The invocation trigger covers 'any financial action' on first use or when something appears missing, which is overly broad and ambiguous. Broad triggers in a privileged financial skill raise the chance of accidental activation, unnecessary file reads, and setup actions being initiated in contexts the user did not specifically authorize.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The skill directs autonomous modification of config.json and .env without an upfront user-facing warning that files will be changed. Unannounced writes are dangerous in any skill, but especially here because they alter financial configuration and secret-handling files, which can affect billing correctness and security posture.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The skill instructs the agent to create or rename a hidden .env file using terminal/file manipulation during setup. Silent creation of secret-bearing hidden files is dangerous because it changes local system state, encourages secret storage, and may bypass user awareness or repository hygiene controls.

Ssd 3

Medium
Confidence
93% confidence
Finding
The skill instructs the agent to read stored customer records and reuse company/personal details in chat responses, generated payloads, and email workflows without emphasizing data minimization. In a billing context, this can lead to overexposure of client identifiers, addresses, emails, and financial details across multiple outputs and channels.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The workflow requires autonomous email sending via another skill, but that capability is omitted from the skill description. Undisclosed outbound communication is particularly risky in a financial context because it can transmit invoice links or client/accounting data without the user understanding that a cross-skill exfiltration path exists.

Static analysis

No suspicious patterns detected.