Skill: bitbrujo/side-peace (version 1.1.1)

--- name: side-peace version: 1.1.0 description: Minimal secure secret handoff. Zero external deps. Human opens browser form, submits secret, agent receives it via temp file. Secret NEVER appears in stdout/logs. --- # Side_Peace 🍒 Dead simple secret handoff from human to AI. No npm packages to trust — just Node.js built-ins. **Key security feature:** Secret is written to a temp file, NEVER printed to stdout. This prevents secrets from appearing in chat logs or command output. ## How It Works 1. Agent runs `node drop.js --label "API Key"` 2. Agent shares the URL with human 3. Human opens URL in browser, pastes secret, submits 4. Secret is saved to temp file (printed path only, not content) 5. Agent reads file, uses secret, deletes file ## Usage ```bash # Basic - secret saved to random temp file node skills/side-peace/drop.js --label "CLAWHUB_TOKEN" # Custom output path node skills/side-peace/drop.js --label "API_KEY" --output /tmp/my-secret.txt # Custom port node skills/side-peace/drop.js --port 4000 --label "TOKEN" ``` ## Reading the Secret After receiving, the secret is in the temp file: ```bash # Read and use (example with clawhub) SECRET=$(cat /tmp/side-peace-xxx.secret) npx clawhub login --token "$SECRET" --no-browser rm /tmp/side-peace-xxx.secret ``` Or one-liner: ```bash cat /tmp/side-peace-xxx.secret | xargs -I{} npx clawhub login --token {} --no-browser; rm /tmp/side-peace-xxx.secret ``` ## Security - **Zero dependencies** — only Node.js built-ins - **Secret never in stdout** — written to file with 0600 permissions - **Memory only until saved** — temp file deleted after use - **One-time** — server exits after receiving - **~60 lines** — fully auditable ## Output ``` 🍒 Side_Peace waiting... Label: CLAWHUB_TOKEN Output: /tmp/side-peace-a1b2c3d4.secret Local: http://localhost:3000 Network: http://192.168.1.94:3000 Waiting for secret... ✓ Secret received and saved. File: /tmp/side-peace-a1b2c3d4.secret (Secret is NOT printed to stdout for security) ``` The secret is in the file. Read it, use it, delete it.

path: drop.js
content: #!/usr/bin/env node
/**
 * Side_Peace 🍒 — Minimal secret handoff (zero deps)
 * 
 * Human opens URL → submits secret → agent reads from temp file
 * Secret NEVER appears in stdout. Fully auditable.
 */

const http = require('http');
const os = require('os');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

// Parse args
const args = process.argv.slice(2);
const getArg = (name, def) => {
  const i = args.indexOf(`--${name}`);
  return i !== -1 && args[i + 1] ? args[i + 1] : def;
};

const PORT = parseInt(getArg('port', '3000'));
const LABEL = getArg('label', 'Secret');
const OUTPUT = getArg('output', path.join(os.tmpdir(), `side-peace-${crypto.randomBytes(8).toString('hex')}.secret`));

// Get local IPs
const getLocalIPs = () => Object.values(os.networkInterfaces())
  .flat()
  .filter(i => i && i.family === 'IPv4' && !i.internal)
  .map(i => i.address);

// HTML form
const html = `<!DOCTYPE html>
<html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Side_Peace</title>
<style>
  body{font-family:system-ui,sans-serif;max-width:400px;margin:60px auto;padding:20px;background:#111;color:#eee;text-align:center}
  .cherry{font-size:120px;margin:0 0 10px;line-height:1}
  h1{margin:0 0 8px;color:#fff;font-size:32px;letter-spacing:2px}
  .label{color:#888;margin:0 0 24px;font-size:14px}
  textarea{width:100%;height:120px;padding:12px;border:1px solid #333;border-radius:8px;font-size:16px;font-family:monospace;background:#1a1a1a;color:#fff;resize:vertical;box-sizing:border-box;text-align:left}
  textarea:focus{outline:none;border-color:#666}
  button{width:100%;padding:14px;background:#dc2626;color:#fff;border:none;border-radius:8px;font-size:16px;cursor:pointer;margin-top:16px}
  button:hover{background:#b91c1c}
  .done{text-align:center;color:#22c55e;font-size:18px;margin-top:40px}
</style></head>
<body>
  <div class="cherry">🍒</div>
  <h1>Side_Peace</h1>
  <p class="label">${LABEL}</p>
  <form method="POST" id="f">
    <textarea name="secret" placeholder="Paste secret here..." autofocus required></textarea>
    <button type="submit">Submit Secret</button>
  </form>
  <script>
    document.getElementById('f').onsubmit=async e=>{
      e.preventDefault();
      const s=e.target.secret.value;
      await fetch('/',{method:'POST',body:s});
      document.body.innerHTML='<div class="done">✓ Sent! You can close this tab.</div>';
    };
  </script>
</body></html>`;

// Server
const server = http.createServer((req, res) => {
  if (req.method === 'GET') {
    res.writeHead(200, { 'Content-Type': 'text/html' });
    res.end(html);
  } else if (req.method === 'POST') {
    let body = '';
    req.on('data', c => body += c);
    req.on('end', () => {
      res.writeHead(200);
      res.end('ok');
      
      // Write secret to file (NOT stdout!)
      fs.writeFileSync(OUTPUT, body.trim(), { mode: 0o600 });
      
      console.log(`\n✓ Secret received and saved.`);
      console.log(`  File: ${OUTPUT}`);
      console.log(`  (Secret is NOT printed to stdout for security)`);
      
      server.close(() => process.exit(0));
    });
  }
});

// Start
server.listen(PORT, '0.0.0.0', () => {
  const ips = getLocalIPs();
  console.log(`🍒 Side_Peace waiting...`);
  console.log(`   Label: ${LABEL}`);
  console.log(`   Output: ${OUTPUT}\n`);
  console.log(`   Local:    http://localhost:${PORT}`);
  ips.forEach(ip => console.log(`   Network:  http://${ip}:${PORT}`));
  console.log(`\nWaiting for secret...`);
});


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)