T09 · Insecure Skill Coding Practices
- Location
scripts/sanmar_tools.py:819- Finding
Purchase-order dry-run output discloses plaintext SanMar credentials
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
This SanMar purchasing skill is purpose-aligned, but it exposes credentials and has several high-impact safety gaps that users should review before installing.
Install only if you are comfortable reviewing and hardening this skill first. At minimum, remove raw credential-bearing payloads from outputs, restrict portal and SFTP destinations, validate SFTP host keys, confine uploaded return images to approved user attachments, and require explicit human approval for purchase orders and any future return submission.
scripts/sanmar_tools.py:819Purchase-order dry-run output discloses plaintext SanMar credentials
scripts/ftp_resolver.py:154SFTP clients authenticate with passwords without verifying the server host key
scripts/sanmar_browser.py:413Return processing accepts unrestricted local file paths for browser upload
scripts/sanmar_browser.py:93Portal credentials can be submitted to an unvalidated configurable base URL
scripts/sanmar_client.py:291Legacy SOAP methods interpolate unescaped credentials and user input into XML
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def pre_submit_po(self, draft: PurchaseOrderDraft) -> CartValidationResult:
payload = self.build_po_envelope(draft, pre_submit=True)
text = self._post_soap(
self.endpoints.po_url(self.credentials.environment),
payload,
soap_action="getPreSubmitInfo",
operation="getPreSubmitInfo",
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def pre_submit_po(self, draft: PurchaseOrderDraft) -> CartValidationResult:
payload = self.build_po_envelope(draft, pre_submit=True)
text = self._post_soap(
self.endpoints.po_url(self.credentials.environment),
payload,
soap_action="getPreSubmitInfo",
operation="getPreSubmitInfo",
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
def pre_submit_po(self, draft: PurchaseOrderDraft) -> CartValidationResult:
payload = self.build_po_envelope(draft, pre_submit=True)
text = self._post_soap(
self.endpoints.po_url(self.credentials.environment),
payload,
soap_action="getPreSubmitInfo",
operation="getPreSubmitInfo",
The submit_po method performs a live external side effect—placing a purchase order with a vendor—without any in-code guardrail, confirmation gate, or dry-run enforcement. In an agent setting, this is dangerous because a prompt-injected or mistaken workflow could convert untrusted input directly into a real order, causing unauthorized purchases or financial loss.
The skill advertises capabilities that clearly require environment-variable access, file reads, and outbound network access, but it does not declare an explicit tool/permission scope. That creates a governance gap: a runtime or reviewer cannot easily enforce least privilege, and the agent may receive broader access than intended for sensitive credentials, local files, and external services.
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.
**If the script itself returns `config_error` / an auth error**, then the
calling connection did not share the credential (or sharing is misconfigured) —
surface that error message to the caller verbatim. Do not ask the user for a key
(on a delegated turn there is no user to ask), and never print a credential
value into the reply.
The document explicitly permits credentials to be supplied inline via tool stdin JSON, which increases the chance that secrets are exposed through agent logs, traces, shell history, debugging output, or upstream telemetry. In this skill context, the risk is heightened because the credentials grant access to ordering, inventory, invoicing, and SFTP surfaces tied to a customer account, enabling unauthorized reads or writes if leaked.
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.
- Prefer explicit timestamps from feed metadata where available.
- If freshness is critical, include source timestamp/date in response payload.
- Never assume a missing record is permanent without checking relevant active/closeout feeds.
## Error handling contract for this SME
The examples explicitly encourage supplying SanMar credentials inline in JSON and via environment variables without any warning about secret-handling risks. Inline credentials can be exposed through shell history, process listings, logs, transcripts, CI output, or copied examples, making accidental credential disclosure plausible in real operator workflows.
The notes explicitly instruct a user to paste full live portal HTML from authenticated review and success pages. That HTML can contain customer contact data, order identifiers, RMA numbers, addresses, labels, hidden form fields, session-scoped tokens, and other sensitive business information, creating an unnecessary data-exfiltration path into the agent workflow. In this skill context, the risk is elevated because the content is captured from a real production return flow with no sandbox, so any copied page data is likely to be live and sensitive.
This markdown file documents a skill that can ingest and process shipment-status files containing ship-to names, addresses, tracking numbers, and line-item costs. Under SQP-2 for markdown files, the description should warn users about privacy or sensitive business data implications, but no such warning is present in this section.
Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.
<LineItem><StyleNo>PC61</StyleNo><StyleSize>S</StyleSize><Quantity>-1</Quantity>
<UnitPrice>5.00</UnitPrice><Amount>-5.00</Amount></LineItem>
</Invoice></S:Body></S:Envelope>"""
invs = _parse_invoices(__import__("xml.etree.ElementTree", fromlist=["fromstring"]).fromstring(xml))
assert len(invs) == 1 and invs[0].invoice_number == "999"
assert invs[0].to_common()["is_credit"] is True # negative total → credit memo
assert single # smoke: replacement produced text
This client sends authentication credentials and business/order query data to external SanMar SOAP endpoints in multiple methods, but the file provides no user-facing confirmation, print/log disclosure, or inline warning that network transmission occurs. Because the code accesses sensitive credentials and performs outbound HTTP calls, the absence of any visible disclosure meets the missing-warning criterion for code files.
These sections describe pulling invoices and importing invoice files containing financial and potentially customer-related data, then forwarding normalized invoice data downstream. The documentation does not include any warning about sensitive financial information, retention, or limiting sharing, even though the behavior could affect user data privacy.
This code file handles sensitive credential inputs, including username, password, customer_number, and ftp_password, and documents fallback to SANMAR_* environment variables. Although the module docstring mentions this behavior, there is no runtime confirmation, warning, or user-facing notice when sensitive credentials are consumed.
This code file defines credential dataclasses containing usernames and passwords and includes a helper that places the password into request payload fields, but there is no accompanying warning, comment, or user-facing disclosure about handling sensitive credential material. For code files, access to credentials can warrant a finding when there is no visible disclosure at all, and this file provides none beyond basic field descriptions.
No suspicious patterns detected.