T09 · Insecure Skill Coding Practices
- Location
scripts/publish.js:94- Finding
Public post publishing lacks code-enforced user confirmation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/publish.js:94-173
Vulnerability Type: Missing authorization confirmation for an externally visible operation
Risk Level: MediumVulnerable Code
js async function main() { const [, , htmlPath] = process.argv; if (!htmlPath) { console.error('Usage: node publish.js <html-file-path>'); process.exit(1); } let content = fs.readFileSync(htmlPath, 'utf-8'); console.log(`Content length: ${content.length} chars`); let session; try { session = requireSession(); } catch (err) { if (err instanceof SessionExpiredError) { console.error(`❌ ${err.message}`); process.exitCode = 2; return; } throw err; } console.log(`Publishing as: ${session.username}`); // Deferred local-image upload: this is the ONLY moment the images // leave the user's machine (compose.js keeps everything local). try { content = await uploadLocalImages(content, htmlPath); } catch (err) { if (err instanceof SessionExpiredError) { console.error(`❌ ${err.message}`); process.exitCode = 2; return; } console.error(`\n❌ Image upload failed: ${err.message}`); console.error(' Nothing was posted. Fix the issue and re-run publish.js ' + '(already-uploaded images are reused, not re-uploaded).'); process.exitCode = 1; return; } const dhInfo = extractDigitalHuman(content); if (dhInfo) console.log(`Digital Human: ${dhInfo.name} | ID: ${dhInfo.id}`); const locInfo = extractLocation(content); if (locInfo) console.log(`Location: ${locInfo.name} (${locInfo.lng}, ${locInfo.lat})`); // Guard: interactive components must use the editor's exact HTML structure, // otherwise the web frontend renders them as plain text. const formatIssues = validateEditorFormat(content); if (formatIssues.length > 0) { console.error('\n❌ Component HTML does not match the platform editor format:'); formatIssues.forEach(i => console ...[truncated 2598 chars]- Remediation
View remediation
Remediation Suggestions
- Require a short-lived approval artifact before publication.
- Bind the approval artifact to:
- The authenticated account identifier.
- A cryptographic hash of the final HTML.
- A hash and path list for all local images.
- The location and public-map visibility settings.
- An expiration time and one-time nonce.
- Have the preview or confirmation stage create the artifact only after explicit user approval.
- Reject publication when the artifact is absent, expired, reused, or does not match the current draft.
- Alternatively, add an interactive confirmation immediately before the first upload and default to refusal in non-interactive environments.
- Provide a
--dry-runmode that performs all local validation without uploading images or creating a post. - Revalidate the draft and image hashes after confirmation to prevent changes between approval and publication.
