T09 · Insecure Skill Coding Practices
- Location
scripts/piccc.mjs:496- Finding
Bearer Credential Disclosure Through an Unrestricted API Base URL Override
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill is mostly aligned with Piccc AI media generation, but it needs review because its credential and network scoping leave real account-token exposure risks.
Install only if you are comfortable linking a Piccc AI account and storing an API key locally. Prefer a pinned or reviewed installation source, avoid setting PICCC_API_BASE_URL or PICCC_AUTH_BASE_URL outside testing, review downloaded output locations, and use auth logout when finished on shared machines.
scripts/piccc.mjs:496Bearer Credential Disclosure Through an Unrestricted API Base URL Override
scripts/piccc.mjs:458Unvalidated Task Output URLs Permit SSRF and Unbounded File Downloads
README.md:16Documentation Recommends an Unpinned Third-Party Installer
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
node_modules/
.env
output/
coverage/
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
test('device authorization saves credentials and uses them automatically', async () => {
const directory = await mkdtemp(join(tmpdir(), 'piccc-skills-auth-'))
const credentialsFile = join(directory, 'credentials.json')
const env = {
PICCC_API_KEY: '',
PICCC_API_BASE_URL: baseUrl,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
test('device authorization saves credentials and uses them automatically', async () => {
const directory = await mkdtemp(join(tmpdir(), 'piccc-skills-auth-'))
const credentialsFile = join(directory, 'credentials.json')
const env = {
PICCC_API_KEY: '',
PICCC_API_BASE_URL: baseUrl,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
test('device authorization saves credentials and uses them automatically', async () => {
const directory = await mkdtemp(join(tmpdir(), 'piccc-skills-auth-'))
const credentialsFile = join(directory, 'credentials.json')
const env = {
PICCC_API_KEY: '',
PICCC_API_BASE_URL: baseUrl,
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
function runRaw(args, env = {}) {
return new Promise((resolveRun, rejectRun) => {
const child = spawn(process.execPath, [resolve(root, script), ...args], {
env: { ...process.env, PICCC_API_KEY: 'test-key', PICCC_API_BASE_URL: baseUrl, ...env },
stdio: ['ignore', 'pipe', 'pipe'],
})
let stdout = ''
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.
The README states that an API key will be created and stored locally, but does not clearly warn users where it is stored, how it is protected, or how to remove it beyond a logout command. This can lead to credential persistence on disk without informed consent, increasing the risk of accidental exposure through backups, shared machines, weak file permissions, or workspace leakage.
The skill invokes shell commands, performs networked API actions, and manages credentials, but it does not declare any explicit tool scope or allowed-tools boundary. That omission weakens least-privilege controls and makes it easier for an agent runtime to grant broader capabilities than are actually required, increasing the blast radius if the skill is misused or the backing script is compromised.
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.
Before the first request, run `node {baseDir}/scripts/piccc.mjs auth status`. If it reports `authenticated: false`:
1. Explain that the user must sign in and approve access in the browser.
2. Run `node {baseDir}/scripts/piccc.mjs auth login` and wait for it to finish. The command opens the authorization page, receives the local callback, saves the API key, and queries the available balance. Do not ask the user to report completion.
3. If the browser cannot be opened, share the displayed link and verification code while the command keeps waiting. Never ask the user to create, copy, or paste an API key.
4. After authorization, read `available_credits` from the result and report the balance in the user's current language.
5. If `available_credits` is unavailable, run `node {baseDir}/scripts/piccc.mjs credits` and then report the returned balance.
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.
1. Explain that the user must sign in and approve access in the browser.
2. Run `node {baseDir}/scripts/piccc.mjs auth login` and wait for it to finish. The command opens the authorization page, receives the local callback, saves the API key, and queries the available balance. Do not ask the user to report completion.
3. If the browser cannot be opened, share the displayed link and verification code while the command keeps waiting. Never ask the user to create, copy, or paste an API key.
4. After authorization, read `available_credits` from the result and report the balance in the user's current language.
5. If `available_credits` is unavailable, run `node {baseDir}/scripts/piccc.mjs credits` and then report the returned balance.
The default prompt automatically instructs the agent to use the external skill to authorize the user's account and disclose available credits, even without a narrowly scoped user request. This can cause unintended skill activation and unnecessary account-linking or data access, especially in systems where default prompts influence agent behavior before explicit consent is obtained.
The callback fetch explicitly sets the Accept-Language header to 'zh-CN', which hard-codes a locale preference in natural-language behavior. This matches the policy category for language/locale violations because no user choice, opt-in, or documented region-specific justification is present in this file.
All user-facing instructions in this file are written in Chinese, with no indication that other languages are supported or that Chinese is required for a region-specific reason. Under the stated policy, forcing a specific language without user choice can be a natural-language policy concern.
The authorization callback page chooses English or Chinese text based on the browser's Accept-Language header, but the HTML document is always declared as lang="zh-CN". This creates a locale policy mismatch because the skill effectively forces a Chinese locale marker without user opt-in, even for English users.
Detected: suspicious.dangerous_exec, suspicious.env_credential_access, suspicious.exposed_secret_literal (+1 more)