T09 · Insecure Skill Coding Practices
- Location
scripts/vendor/weryai-core/client.js:3- Finding
Bearer API Credential Can Be Transmitted to an Arbitrary Configured Host
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The podcast skill mostly matches its stated purpose, but it has under-scoped credential routing and bundled music/upload code outside the declared podcast workflow.
Review this skill before installing. Use it only with the official WeryAI API host, protect WERYAI_API_KEY as a paid account credential, and do not invoke the bundled weryai-music or upload helper code from this podcast package. Expect real submit, audio, and wait runs to consume credits and to send podcast inputs, webhook URLs, caller IDs, and task IDs to WeryAI.
scripts/vendor/weryai-core/client.js:3Bearer API Credential Can Be Transmitted to an Arbitrary Configured Host
scripts/vendor/weryai-podcast/generate-audio.js:18Unvalidated Task Identifiers Can Manipulate Authenticated API Request Paths
scripts/vendor/weryai-core/upload.js:111Bundled Out-of-Scope Upload Module Can Read Local Files and Send Them to Non-Official Hosts
The code’s actual function is narrowly focused on querying /v1/generation/balance and returning available credits/balance. This is materially different from the declared purpose of podcast speaker lookup and podcast text/audio generation workflows. Balance retrieval is an undeclared capability and is unrelated to the stated podcast-generation behavior, so this description does not accurately represent the supplied code chunk.
This code is a UI/data-normalization helper for model display metadata, primarily covering image and video model names. It contains a static override map, string cleanup helpers, and a function to normalize model entries. There is no evidence of podcast-related functionality, no network or API calls, no text/audio generation logic, and no speaker handling. Therefore, the declared description does not accurately represent the actual behavior of this code chunk.
This code chunk does not implement podcast generation, podcast querying, speaker lookup, or text-to-audio orchestration. Its primary function is a generic upload helper for WeryAI resources: it validates allowed file types and size limits, reads local files, posts them to /v1/generation/upload-file, and resolves sources into public URLs. While such upload functionality could be a supporting utility within a broader podcast system, the declared description is narrowly about podcast generation and delivery APIs, and this code exposes a materially different capability—general file upload/source resolution—that is not represented in the description.
The declared description is specifically about generating and querying WeryAI podcasts, including speaker lookup, text generation, audio generation, and end-to-end podcast workflows. The supplied code does none of that. It only normalizes music-generation input fields for a vendor path named weryai-music, including song type detection, style/category merging, and gender/timbre normalization. This is a materially different primary purpose from podcast generation, so the description does not accurately represent the code behavior.
The declared description is specifically about podcast functionality, including speaker lookup, text generation, audio generation, and full podcast workflows. The supplied code instead targets music submission: it validates music input, prepares a payload, resolves/uploads reference_audio, and posts to /v1/generation/music/generate. There is no evidence of podcast-specific APIs, speaker lookup, text generation, multi-speaker orchestration, querying existing podcast jobs, or delivery of podcast outputs. This is a material purpose mismatch, not a minor implementation detail.
The declared description centers on podcast generation and related podcast API operations. However, the provided code is clearly for a music-generation vendor module: it validates submission inputs for songs or instrumental music, enforces allowed music style keys, restricts lyrics usage for instrumental mode, and constructs a payload accordingly. There is no indication of podcast-specific behavior such as speaker lookup, podcast script generation, multi-speaker handling, or podcast delivery/query operations. This is a material purpose mismatch, not merely an implementation detail.
The code only emits a warning when uploading local files to a non-official domain derived from ctx.baseUrl, but still proceeds with the upload. If an attacker can influence configuration or baseUrl, arbitrary local files selected by the skill can be exfiltrated to an attacker-controlled endpoint along with the Authorization bearer token.
The file implements a complete standalone music submission workflow, including payload building, optional file upload resolution, and task submission, despite the skill being described as podcast generation only. In this context, hidden or unjustified extra capabilities are especially risky because they expand the operational surface beyond declared purpose, making abuse, accidental misuse, and evasion of user/admin expectations more likely.
This code submits requests to a music-generation endpoint (/v1/generation/music/generate) inside a skill advertised as podcast-only. That capability mismatch is dangerous because it introduces undeclared functionality that can be invoked under the skill’s trust boundary, potentially enabling unauthorized content generation, billing abuse, or policy bypass if users or orchestrators expect only podcast operations.
The skill declares network access and use of environment variables in metadata, but it does not define an explicit tool scope such as allowed-tools or permissions. That creates an authorization ambiguity: a runtime or orchestrator may grant broader capabilities than reviewers or users expect, which is risky for a paid, networked skill using API secrets.
This code reads a local file and posts it to a remote endpoint using fetch, including an Authorization header. While there is a warning for non-official domains, there is no general disclosure, confirmation prompt, or user-facing log that a local file's contents will be transmitted off the system to the configured service.
The helper treats any HTTP or HTTPS URL as an already-safe public source and returns it without validation. In a podcast-generation skill, that can let untrusted callers direct downstream processing to arbitrary external resources, enabling SSRF-style fetches by the upstream service, unexpected data exfiltration to third parties, or ingestion of attacker-controlled media.
This file describes 'WeryAI Music Runtime' and shared capabilities for a music/ directory, while the skill manifest states the skill is for podcast generation, speaker lookup, and text-to-audio podcast workflows. That indicates a semantic mismatch between the claimed podcast-focused skill purpose and the documented code/module purpose in this file.
The documentation explicitly states this directory stores a shared 'music domain runtime' and references the music/ directory. In the context of a podcast-generator skill, that documentation actively points to a different product/domain intent than the manifest describes.
The normalization logic explicitly supports English and Chinese labels in GENRE_MAP, EMOTION_MAP, and INSTRUMENT_MAP, but there is no natural-language indication that locale behavior is optional or user-selectable. Under the policy rule, hardcoded locale handling can be a concern when a skill implicitly privileges specific languages without documented opt-in or justification.
This code adds webhook_url and caller_id fields to request payloads, which are likely transmitted to an external service. In this file there is no confirmation prompt, logging, comment, or docstring warning users that callback endpoints and identifiers may be sent onward.
Detected: suspicious.env_credential_access