Engagement Information

Scope Definition

Testing Window

Team Members

Rules of Engagement

Findings (0)

🔍

No findings yet. Add your first finding or use a template to get started.

Executive Summary

📊

Add findings in the Finding Builder tab, then generate the executive summary.

Technical Report

📄

Add findings and engagement details first, then generate the full technical report.

Remediation Progress

No findings to track. Add findings in the Finding Builder tab first.

\n3. Submit the post\n4. When any user views the post, the script executes\n5. Verify cookie exfiltration on attacker-controlled server', evidence: 'POST /forum/post HTTP/1.1\nHost: app.example.com\nCookie: session=abc123\n\nmessage=\n\nHTTP/1.1 201 Created\n\n[Viewing the post as another user triggers the script]', remediation: '1. Implement context-aware output encoding (HTML entity encoding, JavaScript encoding, URL encoding)\n2. Use Content Security Policy (CSP) headers to restrict script execution\n3. Sanitize HTML input using a proven library (e.g., DOMPurify)\n4. Set HttpOnly and Secure flags on session cookies\n5. Implement input validation on both client and server side', mitre: 'T1059 - Command and Scripting Interpreter', cwe: 'CWE-79', cvss: { av: 'N', ac: 'L', pr: 'L', ui: 'R', s: 'C', c: 'L', i: 'L', a: 'N' } }, { title: 'Insecure Direct Object Reference (IDOR)', description: 'The application exposes internal object references (such as database IDs) in URLs or API parameters without proper authorization checks. By manipulating these references, an attacker can access data belonging to other users without authorization.', affected: 'api.example.com', component: '/api/v2/users/{id}/profile -- id parameter', steps: '1. Authenticate as testuser (ID: 1001)\n2. Request GET /api/v2/users/1001/profile -- returns own profile\n3. Change ID to 1002: GET /api/v2/users/1002/profile\n4. Observe that another user\'s profile data is returned\n5. Iterate through IDs 1000-2000 to enumerate all user profiles', evidence: 'GET /api/v2/users/1002/profile HTTP/1.1\nHost: api.example.com\nAuthorization: Bearer eyJhbGci...(testuser token)\n\nHTTP/1.1 200 OK\n{\n "id": 1002,\n "name": "Jane Admin",\n "email": "jane@example.com",\n "role": "administrator",\n "ssn": "REDACTED"\n}', remediation: '1. Implement proper authorization checks on every request -- verify the authenticated user has access to the requested resource\n2. Use indirect references (UUIDs) instead of sequential IDs\n3. Implement access control middleware that validates object ownership\n4. Log and alert on sequential access pattern anomalies\n5. Consider implementing rate limiting on sensitive endpoints', mitre: 'T1078 - Valid Accounts', cwe: 'CWE-639', cvss: { av: 'N', ac: 'L', pr: 'L', ui: 'N', s: 'U', c: 'H', i: 'N', a: 'N' } }, { title: 'Broken Authentication', description: 'The application\'s authentication mechanism contains weaknesses that allow attackers to compromise credentials, session tokens, or exploit implementation flaws. No account lockout policy exists, enabling unlimited brute-force attempts.', affected: 'app.example.com', component: '/login endpoint -- authentication mechanism', steps: '1. Identify login endpoint at https://app.example.com/login\n2. Attempt 1000 login attempts with common passwords against admin account -- no lockout triggered\n3. Use Hydra: hydra -l admin -P /usr/share/wordlists/rockyou.txt app.example.com http-post-form "/login:user=^USER^&pass=^PASS^:Invalid"\n4. Successfully authenticate with admin/REDACTED after 847 attempts\n5. Note: no MFA required, no CAPTCHA, no rate limiting', evidence: '$ hydra -l admin -P wordlist.txt 192.0.2.10 http-post-form \\\n "/login:user=^USER^&pass=^PASS^:Invalid credentials"\n\n[80][http-post-form] host: 192.0.2.10 login: admin password: REDACTED\n1 of 1 target successfully completed, 1 valid password found\n\n[No account lockout after 847 failed attempts]', remediation: '1. Implement account lockout after 5 failed attempts (with progressive delays)\n2. Deploy multi-factor authentication (MFA) for all user accounts\n3. Implement CAPTCHA after 3 failed login attempts\n4. Enforce strong password policies (minimum 12 characters, complexity requirements)\n5. Implement rate limiting on authentication endpoints\n6. Use bcrypt/scrypt/argon2 for password hashing', mitre: 'T1110 - Brute Force', cwe: 'CWE-307', cvss: { av: 'N', ac: 'L', pr: 'N', ui: 'N', s: 'U', c: 'H', i: 'H', a: 'N' } }, { title: 'Sensitive Data Exposure', description: 'The application transmits or stores sensitive data without adequate protection. API responses include excessive data, internal debugging information is exposed in production, and sensitive fields are logged in plaintext.', affected: '192.0.2.10, api.example.com', component: '/api/v1/debug, /api/v1/users -- multiple endpoints', steps: '1. Access https://api.example.com/api/v1/debug -- returns full stack traces and environment variables\n2. Request GET /api/v1/users -- response includes password hashes, SSNs, and API keys\n3. Inspect HTTP headers -- Server version disclosed (Apache/2.4.49)\n4. Check /robots.txt -- references /admin, /backup, /config endpoints\n5. Access /config -- returns database connection strings in plaintext', evidence: 'GET /api/v1/debug HTTP/1.1\nHost: api.example.com\n\nHTTP/1.1 200 OK\n{\n "environment": "production",\n "db_host": "db01.example.com",\n "db_password": "REDACTED",\n "aws_key": "REDACTED",\n "stack_trace": "...",\n "internal_ip": "10.0.1.50"\n}', remediation: '1. Remove all debug endpoints from production deployments\n2. Implement response filtering to exclude sensitive fields from API responses\n3. Remove server version headers (ServerTokens Prod)\n4. Encrypt sensitive data at rest and in transit\n5. Implement proper secrets management (HashiCorp Vault, AWS Secrets Manager)\n6. Review and restrict robots.txt entries', mitre: 'T1005 - Data from Local System', cwe: 'CWE-200', cvss: { av: 'N', ac: 'L', pr: 'N', ui: 'N', s: 'U', c: 'H', i: 'N', a: 'N' } }, { title: 'Security Misconfiguration', description: 'Multiple security misconfigurations were identified across the application stack, including default configurations, unnecessary services, overly permissive CORS policies, and missing security hardening.', affected: '192.0.2.10, 192.0.2.11, app.example.com', component: 'Web server, application framework, CORS configuration', steps: '1. Identify open management ports: nmap -sV 192.0.2.10 reveals ports 22, 80, 443, 8080 (Tomcat Manager), 9090 (monitoring)\n2. Access Tomcat Manager at :8080/manager -- default credentials accepted\n3. Check CORS headers -- Access-Control-Allow-Origin: * on all API endpoints\n4. Directory listing enabled on /assets/ and /uploads/ directories\n5. TLS configuration allows TLS 1.0 and weak cipher suites', evidence: '$ nmap -sV 192.0.2.10\nPORT STATE SERVICE VERSION\n22/tcp open ssh OpenSSH 7.4\n80/tcp open http Apache/2.4.49\n443/tcp open ssl/http Apache/2.4.49\n8080/tcp open http Apache Tomcat/9.0.31\n9090/tcp open http Prometheus\n\n$ curl -I https://api.example.com/api/v1/data\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Methods: GET, POST, PUT, DELETE\nAccess-Control-Allow-Headers: *', remediation: '1. Close unnecessary ports and services (8080, 9090)\n2. Change all default credentials and remove default accounts\n3. Implement restrictive CORS policies -- whitelist specific origins\n4. Disable directory listing in web server configuration\n5. Enforce TLS 1.2+ and strong cipher suites only\n6. Implement security headers (HSTS, X-Frame-Options, X-Content-Type-Options)\n7. Conduct regular configuration audits using CIS benchmarks', mitre: 'T1190 - Exploit Public-Facing Application', cwe: 'CWE-16', cvss: { av: 'N', ac: 'L', pr: 'N', ui: 'N', s: 'U', c: 'L', i: 'L', a: 'N' } }, { title: 'Missing Security Headers', description: 'The application does not implement critical HTTP security headers, leaving users vulnerable to clickjacking, MIME-type sniffing, cross-site scripting, and other client-side attacks.', affected: 'app.example.com, api.example.com', component: 'HTTP response headers -- all endpoints', steps: '1. Send request to https://app.example.com/ and inspect response headers\n2. Verify absence of: Strict-Transport-Security, Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy\n3. Confirm site can be framed by external domains (clickjacking)\n4. Test MIME-type sniffing by uploading a .txt file with HTML content', evidence: '$ curl -sI https://app.example.com/ | grep -iE "strict|content-security|x-frame|x-content|referrer|permissions"\n[No matching headers found]\n\nMissing headers:\n- Strict-Transport-Security\n- Content-Security-Policy\n- X-Frame-Options\n- X-Content-Type-Options\n- Referrer-Policy\n- Permissions-Policy\n- X-XSS-Protection (legacy but still recommended)', remediation: '1. Add Strict-Transport-Security: max-age=31536000; includeSubDomains; preload\n2. Implement Content-Security-Policy with restrictive directives\n3. Add X-Frame-Options: DENY (or SAMEORIGIN if framing is needed)\n4. Add X-Content-Type-Options: nosniff\n5. Add Referrer-Policy: strict-origin-when-cross-origin\n6. Add Permissions-Policy to restrict browser features\n7. Configure headers at the reverse proxy/load balancer level for consistency', mitre: 'T1190 - Exploit Public-Facing Application', cwe: 'CWE-693', cvss: { av: 'N', ac: 'L', pr: 'N', ui: 'R', s: 'U', c: 'N', i: 'L', a: 'N' } }, { title: 'Privilege Escalation', description: 'A low-privileged user can escalate to administrative privileges by manipulating API requests. The application relies on client-side role enforcement without server-side validation, allowing horizontal and vertical privilege escalation.', affected: 'api.example.com', component: '/api/v2/users/profile -- role parameter', steps: '1. Authenticate as testuser (role: "viewer")\n2. Intercept profile update request with Burp Suite\n3. Add "role": "admin" to the JSON body\n4. Send modified request: PUT /api/v2/users/profile\n5. Verify role change by requesting /api/v2/admin/dashboard -- access granted\n6. Confirm ability to create/delete users, modify configurations', evidence: 'PUT /api/v2/users/profile HTTP/1.1\nHost: api.example.com\nAuthorization: Bearer eyJhbGci...\nContent-Type: application/json\n\n{"name":"testuser","email":"test@example.com","role":"admin"}\n\nHTTP/1.1 200 OK\n{"status":"updated","role":"admin"}\n\nGET /api/v2/admin/dashboard HTTP/1.1\nHTTP/1.1 200 OK\n{"users_count":1547,"pending_approvals":23}', remediation: '1. Implement server-side role validation -- never trust client-supplied role values\n2. Use role-based access control (RBAC) middleware that checks permissions on every request\n3. Remove role field from user-modifiable profile endpoints\n4. Implement principle of least privilege for all API endpoints\n5. Log and alert on role change attempts\n6. Conduct access control testing as part of CI/CD pipeline', mitre: 'T1068 - Exploitation for Privilege Escalation', cwe: 'CWE-269', cvss: { av: 'N', ac: 'L', pr: 'L', ui: 'N', s: 'U', c: 'H', i: 'H', a: 'H' } }, { title: 'Default Credentials', description: 'Multiple systems and services are accessible using vendor default or commonly-known credentials. This provides unauthorized access to administrative interfaces and sensitive configuration.', affected: '192.0.2.10, 192.0.2.11, 192.0.2.20', component: 'Tomcat Manager, SNMP, database, network devices', steps: '1. Scan for management interfaces using nmap\n2. Test Tomcat Manager (192.0.2.10:8080) -- admin/admin grants access\n3. Test SNMP (192.0.2.11) -- community string "public" returns full system info\n4. Test PostgreSQL (192.0.2.10:5432) -- postgres/REDACTED grants superuser access\n5. Test network switch (192.0.2.20) -- admin/REDACTED grants configuration access', evidence: '$ curl -u admin:REDACTED https://192.0.2.10:8080/manager/html\nHTTP/1.1 200 OK\n[Tomcat Manager dashboard rendered]\n\n$ snmpwalk -v2c -c public 192.0.2.11\nSNMPv2-MIB::sysDescr.0 = STRING: Linux srv01.example.com 5.4.0\nSNMPv2-MIB::sysContact.0 = STRING: admin@example.com\n...\n\n$ psql -h 192.0.2.10 -U postgres -c "SELECT version();"\n PostgreSQL 13.4 on x86_64-pc-linux-gnu', remediation: '1. Change ALL default credentials immediately on all systems and services\n2. Implement a credential management policy requiring unique, strong passwords\n3. Disable SNMP v1/v2c -- use SNMPv3 with authentication and encryption\n4. Restrict management interface access to management VLAN only\n5. Implement network segmentation to isolate management interfaces\n6. Deploy privileged access management (PAM) solution\n7. Conduct regular default credential audits', mitre: 'T1078 - Valid Accounts', cwe: 'CWE-798', cvss: { av: 'N', ac: 'L', pr: 'N', ui: 'N', s: 'U', c: 'H', i: 'H', a: 'H' } }, { title: 'Unpatched Software', description: 'Multiple systems are running outdated software versions with known vulnerabilities. Several CVEs with public exploits are applicable to the identified versions, posing significant risk of remote code execution.', affected: '192.0.2.10, 192.0.2.11, 198.51.100.5', component: 'Apache 2.4.49, OpenSSH 7.4, jQuery 2.1.4, PHP 7.3', steps: '1. Identify service versions via banner grabbing: nmap -sV target\n2. Apache 2.4.49 -- vulnerable to CVE-2021-41773 (path traversal/RCE)\n3. OpenSSH 7.4 -- vulnerable to CVE-2018-15473 (user enumeration)\n4. jQuery 2.1.4 -- vulnerable to CVE-2020-11022 (XSS via HTML)\n5. PHP 7.3 -- EOL, multiple known CVEs\n6. Cross-reference versions against NVD and exploit-db', evidence: '$ nmap -sV 192.0.2.10\nPORT STATE SERVICE VERSION\n22/tcp open ssh OpenSSH 7.4 (protocol 2.0)\n80/tcp open http Apache/2.4.49\n443/tcp open ssl Apache/2.4.49\n\n$ curl https://app.example.com/ | grep -i jquery\n\n\n$ curl -s https://192.0.2.10/cgi-bin/.%2e/%2e%2e/etc/passwd\nroot:x:0:0:root:/root:/bin/bash\n[CVE-2021-41773 path traversal confirmed]', remediation: '1. Upgrade Apache to latest stable version (2.4.58+)\n2. Upgrade OpenSSH to 9.x series\n3. Upgrade jQuery to 3.7.x or later\n4. Migrate from PHP 7.3 (EOL) to PHP 8.2+\n5. Implement automated vulnerability scanning in CI/CD pipeline\n6. Establish a patch management policy with defined SLAs:\n - Critical: 24-48 hours\n - High: 7 days\n - Medium: 30 days\n - Low: 90 days\n7. Subscribe to vendor security advisories', mitre: 'T1190 - Exploit Public-Facing Application', cwe: 'CWE-1104', cvss: { av: 'N', ac: 'L', pr: 'N', ui: 'N', s: 'U', c: 'H', i: 'H', a: 'H' } } ]; // ── CVSS 3.1 Calculator ── function rtgCalcCVSS() { var av = document.getElementById('rtg-cvss-av').value; var ac = document.getElementById('rtg-cvss-ac').value; var pr = document.getElementById('rtg-cvss-pr').value; var ui = document.getElementById('rtg-cvss-ui').value; var s = document.getElementById('rtg-cvss-s').value; var c = document.getElementById('rtg-cvss-c').value; var i = document.getElementById('rtg-cvss-i').value; var a = document.getElementById('rtg-cvss-a').value; var avScores = { N: 0.85, A: 0.62, L: 0.55, P: 0.20 }; var acScores = { L: 0.77, H: 0.44 }; var prScoresU = { N: 0.85, L: 0.62, H: 0.27 }; var prScoresC = { N: 0.85, L: 0.68, H: 0.50 }; var uiScores = { N: 0.85, R: 0.62 }; var ciaScores = { H: 0.56, L: 0.22, N: 0 }; var prScores = (s === 'C') ? prScoresC : prScoresU; var iss = 1 - ((1 - ciaScores[c]) * (1 - ciaScores[i]) * (1 - ciaScores[a])); var impact, exploitability, score; exploitability = 8.22 * avScores[av] * acScores[ac] * prScores[pr] * uiScores[ui]; if (s === 'U') { impact = 6.42 * iss; } else { impact = 7.52 * (iss - 0.029) - 3.25 * Math.pow(iss - 0.02, 15); } if (impact <= 0) { score = 0; } else if (s === 'U') { score = Math.min(impact + exploitability, 10); score = Math.ceil(score * 10) / 10; } else { score = Math.min(1.08 * (impact + exploitability), 10); score = Math.ceil(score * 10) / 10; } var severity, color; if (score === 0) { severity = 'NONE'; color = '#8892b0'; } else if (score <= 3.9) { severity = 'LOW'; color = '#66bb6a'; } else if (score <= 6.9) { severity = 'MEDIUM'; color = '#ffa726'; } else if (score <= 8.9) { severity = 'HIGH'; color = '#ff6b35'; } else { severity = 'CRITICAL'; color = '#ff4444'; } document.getElementById('rtg-cvss-score-display').textContent = score.toFixed(1); document.getElementById('rtg-cvss-score-display').style.color = color; document.getElementById('rtg-cvss-severity-display').textContent = severity; document.getElementById('rtg-cvss-severity-display').style.color = color; document.getElementById('rtg-cvss-vector-display').textContent = 'CVSS:3.1/AV:' + av + '/AC:' + ac + '/PR:' + pr + '/UI:' + ui + '/S:' + s + '/C:' + c + '/I:' + i + '/A:' + a; return { score: score, severity: severity, vector: 'CVSS:3.1/AV:' + av + '/AC:' + ac + '/PR:' + pr + '/UI:' + ui + '/S:' + s + '/C:' + c + '/I:' + i + '/A:' + a }; } window.rtgCalcCVSS = rtgCalcCVSS; // ── Tab Switching ── window.rtgSwitchTab = function(tabId) { var tabs = document.querySelectorAll('.rtg-tab-content'); var btns = document.querySelectorAll('.rtg-tab-btn'); for (var t = 0; t < tabs.length; t++) tabs[t].classList.remove('active'); for (var b = 0; b < btns.length; b++) btns[b].classList.remove('active'); document.getElementById('tab-' + tabId).classList.add('active'); var tabNames = ['setup', 'findings', 'executive', 'technical', 'remediation']; var idx = tabNames.indexOf(tabId); if (idx >= 0) btns[idx].classList.add('active'); }; // ── Notifications ── function rtgNotify(msg, type) { var el = document.getElementById('rtg-notification'); el.textContent = msg; el.className = 'rtg-notification rtg-notification-' + (type || 'success') + ' show'; setTimeout(function() { el.classList.remove('show'); }, 3000); } // ── Engagement ── window.rtgSaveEngagement = function() { rtgState.engagement = { client: document.getElementById('rtg-client-name').value, engagementId: document.getElementById('rtg-engagement-id').value, classification: document.getElementById('rtg-classification').value, version: document.getElementById('rtg-report-version').value, scopeIn: document.getElementById('rtg-scope-in').value, scopeOut: document.getElementById('rtg-scope-out').value, testType: document.getElementById('rtg-test-type').value, methodology: document.getElementById('rtg-methodology').value, startDate: document.getElementById('rtg-start-date').value, endDate: document.getElementById('rtg-end-date').value, reportDate: document.getElementById('rtg-report-date').value, leadTester: document.getElementById('rtg-lead-tester').value, teamMembers: document.getElementById('rtg-team-members').value, roe: document.getElementById('rtg-roe').value, clientPoc: document.getElementById('rtg-client-poc').value }; rtgNotify('Engagement details saved successfully'); }; window.rtgLoadSampleEngagement = function() { document.getElementById('rtg-client-name').value = 'ExampleCorp International'; document.getElementById('rtg-engagement-id').value = 'PT-2026-042'; document.getElementById('rtg-classification').value = 'CONFIDENTIAL'; document.getElementById('rtg-report-version').value = '1.0 DRAFT'; document.getElementById('rtg-scope-in').value = '192.0.2.0/24 -- External perimeter\n198.51.100.0/24 -- Internal corporate network\n203.0.113.0/24 -- DMZ segment\napp.example.com -- Primary web application\napi.example.com -- REST API endpoint\nmail.example.com -- Mail gateway\nvpn.example.com -- VPN concentrator\nad.example.com -- Active Directory domain controller'; document.getElementById('rtg-scope-out').value = 'Production database servers (db01.example.com, db02.example.com)\nThird-party SaaS integrations\nPhysical security testing\nSocial engineering via phone'; document.getElementById('rtg-test-type').value = 'Web Application Assessment'; document.getElementById('rtg-methodology').value = 'PTES (Penetration Testing Execution Standard)'; document.getElementById('rtg-start-date').value = '2026-03-10'; document.getElementById('rtg-end-date').value = '2026-03-21'; document.getElementById('rtg-report-date').value = '2026-03-24'; document.getElementById('rtg-lead-tester').value = 'Alex Chen, OSCP, GPEN'; document.getElementById('rtg-team-members').value = 'Jordan Rivera (GWAPT), Sam Kim (OSWE)'; document.getElementById('rtg-roe').value = '1. Testing hours: 09:00-17:00 EST, Monday-Friday only\n2. No denial-of-service attacks against production systems\n3. No data exfiltration of actual customer/employee PII\n4. Credential brute-force limited to 10 attempts per account\n5. Any critical findings reported immediately via encrypted email to security@example.com\n6. Emergency contact: CISO Jane Smith -- +1-555-0100\n7. All testing traffic must originate from approved source IPs: 198.51.100.50-55\n8. Screenshots of all significant findings required as evidence'; document.getElementById('rtg-client-poc').value = 'Jane Smith, CISO -- jane.smith@example.com -- +1-555-0100'; rtgNotify('Sample engagement data loaded'); }; // ── Finding Form ── window.rtgShowFindingForm = function() { document.getElementById('rtg-finding-form').style.display = 'block'; document.getElementById('rtg-template-panel').style.display = 'none'; if (rtgState.editingIndex === -1) { rtgClearFindingForm(); document.getElementById('rtg-f-id').value = 'FINDING-' + String(rtgState.nextFindingId).padStart(3, '0'); } }; window.rtgCancelFinding = function() { document.getElementById('rtg-finding-form').style.display = 'none'; rtgState.editingIndex = -1; rtgClearFindingForm(); }; function rtgClearFindingForm() { document.getElementById('rtg-f-title').value = ''; document.getElementById('rtg-f-id').value = 'FINDING-' + String(rtgState.nextFindingId).padStart(3, '0'); document.getElementById('rtg-f-description').value = ''; document.getElementById('rtg-f-affected').value = ''; document.getElementById('rtg-f-component').value = ''; document.getElementById('rtg-f-steps').value = ''; document.getElementById('rtg-f-evidence').value = ''; document.getElementById('rtg-f-screenshot').value = ''; document.getElementById('rtg-f-remediation').value = ''; document.getElementById('rtg-f-mitre').value = ''; document.getElementById('rtg-f-status').value = 'Open'; document.getElementById('rtg-f-cwe').value = ''; document.getElementById('rtg-f-owner').value = ''; document.getElementById('rtg-f-due-date').value = ''; document.getElementById('rtg-cvss-av').value = 'N'; document.getElementById('rtg-cvss-ac').value = 'L'; document.getElementById('rtg-cvss-pr').value = 'N'; document.getElementById('rtg-cvss-ui').value = 'N'; document.getElementById('rtg-cvss-s').value = 'U'; document.getElementById('rtg-cvss-c').value = 'H'; document.getElementById('rtg-cvss-i').value = 'H'; document.getElementById('rtg-cvss-a').value = 'N'; rtgCalcCVSS(); } // ── Templates ── window.rtgShowTemplates = function() { document.getElementById('rtg-template-panel').style.display = 'block'; document.getElementById('rtg-finding-form').style.display = 'none'; var grid = document.getElementById('rtg-template-grid'); var html = ''; for (var t = 0; t < rtgTemplates.length; t++) { html += '
' + '
' + (t + 1) + '. ' + rtgTemplates[t].title + '
' + '
' + rtgTemplates[t].description.substring(0, 120) + '...
' + '
'; } grid.innerHTML = html; }; window.rtgHideTemplates = function() { document.getElementById('rtg-template-panel').style.display = 'none'; }; window.rtgApplyTemplate = function(idx) { var tmpl = rtgTemplates[idx]; document.getElementById('rtg-finding-form').style.display = 'block'; document.getElementById('rtg-template-panel').style.display = 'none'; document.getElementById('rtg-f-title').value = tmpl.title; document.getElementById('rtg-f-id').value = 'FINDING-' + String(rtgState.nextFindingId).padStart(3, '0'); document.getElementById('rtg-f-description').value = tmpl.description; document.getElementById('rtg-f-affected').value = tmpl.affected; document.getElementById('rtg-f-component').value = tmpl.component; document.getElementById('rtg-f-steps').value = tmpl.steps; document.getElementById('rtg-f-evidence').value = tmpl.evidence; document.getElementById('rtg-f-remediation').value = tmpl.remediation; document.getElementById('rtg-f-mitre').value = tmpl.mitre; document.getElementById('rtg-f-cwe').value = tmpl.cwe; if (tmpl.cvss) { document.getElementById('rtg-cvss-av').value = tmpl.cvss.av; document.getElementById('rtg-cvss-ac').value = tmpl.cvss.ac; document.getElementById('rtg-cvss-pr').value = tmpl.cvss.pr; document.getElementById('rtg-cvss-ui').value = tmpl.cvss.ui; document.getElementById('rtg-cvss-s').value = tmpl.cvss.s; document.getElementById('rtg-cvss-c').value = tmpl.cvss.c; document.getElementById('rtg-cvss-i').value = tmpl.cvss.i; document.getElementById('rtg-cvss-a').value = tmpl.cvss.a; rtgCalcCVSS(); } rtgNotify('Template "' + tmpl.title + '" applied'); }; // ── Save Finding ── window.rtgSaveFinding = function() { var title = document.getElementById('rtg-f-title').value.trim(); if (!title) { rtgNotify('Finding title is required', 'error'); return; } var cvssResult = rtgCalcCVSS(); var finding = { id: document.getElementById('rtg-f-id').value, title: title, description: document.getElementById('rtg-f-description').value, affected: document.getElementById('rtg-f-affected').value, component: document.getElementById('rtg-f-component').value, steps: document.getElementById('rtg-f-steps').value, evidence: document.getElementById('rtg-f-evidence').value, screenshot: document.getElementById('rtg-f-screenshot').value, remediation: document.getElementById('rtg-f-remediation').value, mitre: document.getElementById('rtg-f-mitre').value, status: document.getElementById('rtg-f-status').value, cwe: document.getElementById('rtg-f-cwe').value, owner: document.getElementById('rtg-f-owner').value, dueDate: document.getElementById('rtg-f-due-date').value, cvssScore: cvssResult.score, severity: cvssResult.severity, cvssVector: cvssResult.vector, cvssMetrics: { av: document.getElementById('rtg-cvss-av').value, ac: document.getElementById('rtg-cvss-ac').value, pr: document.getElementById('rtg-cvss-pr').value, ui: document.getElementById('rtg-cvss-ui').value, s: document.getElementById('rtg-cvss-s').value, c: document.getElementById('rtg-cvss-c').value, i: document.getElementById('rtg-cvss-i').value, a: document.getElementById('rtg-cvss-a').value } }; if (rtgState.editingIndex >= 0) { rtgState.findings[rtgState.editingIndex] = finding; rtgState.editingIndex = -1; rtgNotify('Finding updated successfully'); } else { rtgState.findings.push(finding); rtgState.nextFindingId++; rtgNotify('Finding "' + title + '" added successfully'); } document.getElementById('rtg-finding-form').style.display = 'none'; rtgClearFindingForm(); rtgRenderFindings(); }; // ── Render Findings List ── function rtgRenderFindings() { var list = document.getElementById('rtg-findings-list'); document.getElementById('rtg-finding-count').textContent = rtgState.findings.length; if (rtgState.findings.length === 0) { list.innerHTML = '
🔍

No findings yet. Add your first finding or use a template to get started.

'; return; } var sorted = rtgState.findings.slice().sort(function(a, b) { return b.cvssScore - a.cvssScore; }); var html = ''; for (var f = 0; f < sorted.length; f++) { var finding = sorted[f]; var sevClass = finding.severity.toLowerCase(); var statClass = finding.status.toLowerCase().replace(/\s+/g, '-'); var origIdx = rtgState.findings.indexOf(finding); html += '
' + '
' + '
' + '' + finding.severity + ' (' + finding.cvssScore.toFixed(1) + ')' + ' ' + finding.status + '' + '
' + '
' + '' + '' + '
' + '
' + '
' + finding.id + ': ' + finding.title + '
' + '
' + 'Affected: ' + finding.affected + (finding.mitre ? ' | ATT&CK: ' + finding.mitre : '') + (finding.cwe ? ' | ' + finding.cwe + '' : '') + '
' + '
'; } list.innerHTML = html; } // ── Edit / Delete ── window.rtgEditFinding = function(idx) { var f = rtgState.findings[idx]; rtgState.editingIndex = idx; document.getElementById('rtg-f-title').value = f.title; document.getElementById('rtg-f-id').value = f.id; document.getElementById('rtg-f-description').value = f.description; document.getElementById('rtg-f-affected').value = f.affected; document.getElementById('rtg-f-component').value = f.component; document.getElementById('rtg-f-steps').value = f.steps; document.getElementById('rtg-f-evidence').value = f.evidence; document.getElementById('rtg-f-screenshot').value = f.screenshot; document.getElementById('rtg-f-remediation').value = f.remediation; document.getElementById('rtg-f-mitre').value = f.mitre; document.getElementById('rtg-f-status').value = f.status; document.getElementById('rtg-f-cwe').value = f.cwe; document.getElementById('rtg-f-owner').value = f.owner; document.getElementById('rtg-f-due-date').value = f.dueDate; if (f.cvssMetrics) { document.getElementById('rtg-cvss-av').value = f.cvssMetrics.av; document.getElementById('rtg-cvss-ac').value = f.cvssMetrics.ac; document.getElementById('rtg-cvss-pr').value = f.cvssMetrics.pr; document.getElementById('rtg-cvss-ui').value = f.cvssMetrics.ui; document.getElementById('rtg-cvss-s').value = f.cvssMetrics.s; document.getElementById('rtg-cvss-c').value = f.cvssMetrics.c; document.getElementById('rtg-cvss-i').value = f.cvssMetrics.i; document.getElementById('rtg-cvss-a').value = f.cvssMetrics.a; } rtgCalcCVSS(); document.getElementById('rtg-finding-form').style.display = 'block'; document.getElementById('rtg-template-panel').style.display = 'none'; }; window.rtgDeleteFinding = function(idx) { if (confirm('Delete finding "' + rtgState.findings[idx].title + '"?')) { rtgState.findings.splice(idx, 1); rtgRenderFindings(); rtgNotify('Finding deleted'); } }; // ── Executive Summary Generation ── window.rtgGenerateExecutive = function() { if (rtgState.findings.length === 0) { rtgNotify('Add findings before generating the executive summary', 'error'); return; } rtgSaveEngagement(); var eng = rtgState.engagement; var findings = rtgState.findings; var counts = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0, NONE: 0 }; var openCount = 0; for (var f = 0; f < findings.length; f++) { var sev = findings[f].severity; if (counts.hasOwnProperty(sev)) counts[sev]++; if (findings[f].status === 'Open') openCount++; } var maxCount = Math.max(counts.CRITICAL, counts.HIGH, counts.MEDIUM, counts.LOW, 1); var overallRisk = 'Low'; if (counts.CRITICAL > 0) overallRisk = 'Critical'; else if (counts.HIGH > 0) overallRisk = 'High'; else if (counts.MEDIUM > 0) overallRisk = 'Medium'; var riskColor = { Critical: '#ff4444', High: '#ff6b35', Medium: '#ffa726', Low: '#66bb6a' }; // Sort by severity for top findings var sorted = findings.slice().sort(function(a, b) { return b.cvssScore - a.cvssScore; }); var top5 = sorted.slice(0, 5); var html = ''; // Stats Grid html += '
' + '
' + findings.length + '
Total Findings
' + '
' + counts.CRITICAL + '
Critical
' + '
' + counts.HIGH + '
High
' + '
' + overallRisk + '
Overall Risk
' + '
'; // Risk Distribution Chart html += '

Risk Distribution

'; html += '
'; var bars = [ { label: 'Critical', count: counts.CRITICAL, color: '#ff4444' }, { label: 'High', count: counts.HIGH, color: '#ff6b35' }, { label: 'Medium', count: counts.MEDIUM, color: '#ffa726' }, { label: 'Low', count: counts.LOW, color: '#66bb6a' }, { label: 'Info', count: counts.NONE || 0, color: '#42a5f5' } ]; for (var b = 0; b < bars.length; b++) { var heightPct = maxCount > 0 ? (bars[b].count / maxCount) * 160 : 0; html += '
' + '
' + '
' + bars[b].count + '
' + '
' + '
' + bars[b].label + '
' + '
'; } html += '
'; // Top Critical Findings html += '

Top ' + top5.length + ' Critical Findings

'; html += '
' + ''; for (var t = 0; t < top5.length; t++) { var sevC = top5[t].severity.toLowerCase(); var stC = top5[t].status.toLowerCase().replace(/\s+/g, '-'); html += '' + '' + '' + ''; } html += '
#FindingCVSSSeverityStatus
' + (t + 1) + '' + top5[t].title + '' + top5[t].cvssScore.toFixed(1) + '' + top5[t].severity + '' + top5[t].status + '
'; // Key Recommendations html += '

Key Recommendations

'; html += '
'; html += '
    '; if (counts.CRITICAL > 0) html += '
  1. Immediate Action Required: Address all ' + counts.CRITICAL + ' critical findings within 48 hours. These vulnerabilities pose an immediate risk of exploitation.
  2. '; if (counts.HIGH > 0) html += '
  3. High Priority: Remediate ' + counts.HIGH + ' high-severity findings within 7 business days.
  4. '; if (counts.MEDIUM > 0) html += '
  5. Medium Priority: Schedule remediation of ' + counts.MEDIUM + ' medium-severity findings within 30 days.
  6. '; html += '
  7. Security Program: Implement regular vulnerability assessment and penetration testing on a quarterly basis.
  8. '; html += '
  9. Verification: Schedule a retest engagement to verify remediation of all findings.
  10. '; html += '
'; // Engagement Overview html += '

Engagement Overview

'; html += '
' + '' + '' + '' + '' + '' + '' + '
Client' + (eng.client || 'Not specified') + '
Test Type' + (eng.testType || 'Not specified') + '
Methodology' + (eng.methodology || 'Not specified') + '
Testing Period' + (eng.startDate || '?') + ' to ' + (eng.endDate || '?') + '
Lead Tester' + (eng.leadTester || 'Not specified') + '
Open Findings' + openCount + ' of ' + findings.length + '
'; document.getElementById('rtg-exec-content').innerHTML = html; rtgNotify('Executive summary generated'); }; // ── Technical Report Generation ── window.rtgGenerateTechnical = function() { if (rtgState.findings.length === 0) { rtgNotify('Add findings before generating the technical report', 'error'); return; } rtgSaveEngagement(); var eng = rtgState.engagement; var findings = rtgState.findings.slice().sort(function(a, b) { return b.cvssScore - a.cvssScore; }); var html = '
'; // Title Page html += '

PENETRATION TEST REPORT

'; html += '' + '' + '' + '' + '' + '' + '
Client:' + (eng.client || 'Not specified') + '
Engagement ID:' + (eng.engagementId || 'N/A') + '
Classification:' + (eng.classification || 'CONFIDENTIAL') + '
Version:' + (eng.version || '1.0') + '
Report Date:' + (eng.reportDate || new Date().toISOString().split('T')[0]) + '
Lead Tester:' + (eng.leadTester || 'Not specified') + '
Team:' + (eng.teamMembers || 'Not specified') + '
'; // Table of Contents html += '

Table of Contents

'; html += '

1. Executive Summary
2. Methodology
3. Scope
4. Rules of Engagement
5. Findings Summary
'; for (var t = 0; t < findings.length; t++) { html += '  5.' + (t + 1) + ' ' + findings[t].title + '
'; } html += '6. Conclusion
7. Appendices

'; // Section 1: Executive Summary html += '

1. Executive Summary

'; var counts = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0, NONE: 0 }; for (var c = 0; c < findings.length; c++) { if (counts.hasOwnProperty(findings[c].severity)) counts[findings[c].severity]++; } html += '

' + (eng.client || 'The client') + ' engaged the security assessment team to perform a ' + (eng.testType || 'penetration test') + ' of their environment. Testing was conducted between ' + (eng.startDate || '[start date]') + ' and ' + (eng.endDate || '[end date]') + ' using the ' + (eng.methodology || 'PTES') + ' methodology.

'; html += '

A total of ' + findings.length + ' findings were identified: ' + counts.CRITICAL + ' Critical, ' + counts.HIGH + ' High, ' + counts.MEDIUM + ' Medium, and ' + counts.LOW + ' Low severity. '; if (counts.CRITICAL > 0) { html += 'The presence of critical-severity findings indicates that immediate remediation action is required to prevent potential compromise.

'; } else if (counts.HIGH > 0) { html += 'High-severity findings should be addressed within the defined SLA to reduce organizational risk.

'; } else { html += 'The overall security posture is reasonable, though identified findings should still be addressed in a timely manner.

'; } // Section 2: Methodology html += '

2. Methodology

'; html += '

The assessment followed the ' + (eng.methodology || 'PTES') + ' framework and included the following phases:

'; html += '

Phase 1 -- Reconnaissance: Passive and active information gathering to identify the target attack surface, including DNS enumeration, port scanning, service fingerprinting, and OSINT collection.

'; html += '

Phase 2 -- Vulnerability Analysis: Systematic identification of vulnerabilities through automated scanning (Nessus, Burp Suite) and manual testing. Each potential vulnerability was verified to eliminate false positives.

'; html += '

Phase 3 -- Exploitation: Controlled exploitation of confirmed vulnerabilities to demonstrate business impact. All exploitation was conducted within the agreed rules of engagement.

'; html += '

Phase 4 -- Post-Exploitation: Assessment of the potential impact following successful exploitation, including lateral movement possibilities, privilege escalation paths, and data access.

'; html += '

Phase 5 -- Reporting: Documentation of all findings with evidence, risk ratings, and actionable remediation recommendations.

'; // Section 3: Scope html += '

3. Scope

'; html += '

In-Scope Systems

'; html += '

' + (eng.scopeIn || 'Not defined').replace(/'; html += '

Out-of-Scope Systems

'; html += '

' + (eng.scopeOut || 'Not defined').replace(/'; // Section 4: Rules of Engagement html += '

4. Rules of Engagement

'; html += '

' + (eng.roe || 'Standard rules of engagement apply.').replace(/'; // Section 5: Findings html += '

5. Detailed Findings

'; html += ''; for (var s = 0; s < findings.length; s++) { html += ''; } html += '
IDTitleCVSSSeverityStatus
' + findings[s].id + '' + findings[s].title + '' + findings[s].cvssScore.toFixed(1) + '' + findings[s].severity + '' + findings[s].status + '
'; for (var d = 0; d < findings.length; d++) { var fi = findings[d]; html += '

5.' + (d + 1) + ' ' + fi.title + '

'; html += '' + '' + '' + '' + '' + '' + (fi.cwe ? '' : '') + (fi.mitre ? '' : '') + '' + '
Finding ID:' + fi.id + '
Severity:' + fi.severity + ' (CVSS ' + fi.cvssScore.toFixed(1) + ')
CVSS Vector:' + fi.cvssVector + '
Affected Systems:' + fi.affected + '
Component:' + fi.component + '
CWE:' + fi.cwe + '
MITRE ATT&CK:' + fi.mitre + '
Status:' + fi.status + '
'; html += '

Description

' + fi.description.replace(/\n/g, '
') + '

'; if (fi.steps) html += '

Steps to Reproduce

' + fi.steps.replace(/'; if (fi.evidence) html += '

Evidence

' + fi.evidence.replace(/'; if (fi.screenshot) html += '

' + fi.screenshot + '

'; html += '

Remediation

' + fi.remediation.replace(/'; } // Section 6: Conclusion html += '

6. Conclusion

'; html += '

This penetration test identified ' + findings.length + ' security findings across the in-scope environment. '; if (counts.CRITICAL > 0) { html += 'The discovery of ' + counts.CRITICAL + ' critical-severity vulnerabilities indicates significant security gaps that require immediate attention. '; } html += 'It is recommended that all findings be remediated according to the priority levels outlined in this report, followed by a verification retest to confirm successful remediation.

'; html += '

The assessment team is available to provide additional context, answer questions, and support the remediation process as needed.

'; // Section 7: Appendices html += '

7. Appendices

'; html += '

Appendix A: Tool List

'; html += '

The following tools were used during this engagement:

'; html += '' + '' + '' + '' + '' + '' + '' + '' + '' + '
ToolPurposeVersion
NmapPort scanning and service enumeration7.94
Burp Suite ProfessionalWeb application testing2024.1
Nessus ProfessionalVulnerability scanning10.7
sqlmapSQL injection testing1.8
HydraAuthentication testing9.5
Metasploit FrameworkExploitation framework6.4
NiktoWeb server scanning2.5
CrackMapExecActive Directory assessment5.4
'; html += '

Appendix B: CVSS 3.1 Scoring Reference

'; html += '' + '' + '' + '' + '' + '' + '
Score RangeSeverityRecommended SLA
9.0 - 10.0Critical24-48 hours
7.0 - 8.9High7 days
4.0 - 6.9Medium30 days
0.1 - 3.9Low90 days
0.0InformationalBest effort
'; html += '
'; document.getElementById('rtg-tech-content').innerHTML = html; rtgNotify('Technical report generated'); }; // ── Export Report ── window.rtgExportReport = function() { if (rtgState.findings.length === 0) { rtgNotify('Generate the technical report first', 'error'); return; } rtgSaveEngagement(); var eng = rtgState.engagement; var findings = rtgState.findings.slice().sort(function(a, b) { return b.cvssScore - a.cvssScore; }); var sep = '═'.repeat(72); var text = ''; text += sep + '\n'; text += ' PENETRATION TEST REPORT\n'; text += ' ' + (eng.classification || 'CONFIDENTIAL') + '\n'; text += sep + '\n\n'; text += 'Client: ' + (eng.client || 'Not specified') + '\n'; text += 'Engagement ID: ' + (eng.engagementId || 'N/A') + '\n'; text += 'Version: ' + (eng.version || '1.0') + '\n'; text += 'Report Date: ' + (eng.reportDate || new Date().toISOString().split('T')[0]) + '\n'; text += 'Lead Tester: ' + (eng.leadTester || 'Not specified') + '\n'; text += 'Team: ' + (eng.teamMembers || 'Not specified') + '\n\n'; text += sep + '\n'; text += ' EXECUTIVE SUMMARY\n'; text += sep + '\n\n'; var counts = { CRITICAL: 0, HIGH: 0, MEDIUM: 0, LOW: 0, NONE: 0 }; for (var c = 0; c < findings.length; c++) { if (counts.hasOwnProperty(findings[c].severity)) counts[findings[c].severity]++; } text += 'Total Findings: ' + findings.length + '\n'; text += ' Critical: ' + counts.CRITICAL + '\n'; text += ' High: ' + counts.HIGH + '\n'; text += ' Medium: ' + counts.MEDIUM + '\n'; text += ' Low: ' + counts.LOW + '\n\n'; text += sep + '\n'; text += ' SCOPE\n'; text += sep + '\n\n'; text += 'Test Type: ' + (eng.testType || 'Not specified') + '\n'; text += 'Methodology: ' + (eng.methodology || 'Not specified') + '\n'; text += 'Period: ' + (eng.startDate || '?') + ' to ' + (eng.endDate || '?') + '\n\n'; text += 'In-Scope:\n' + (eng.scopeIn || 'Not defined') + '\n\n'; text += 'Out-of-Scope:\n' + (eng.scopeOut || 'Not defined') + '\n\n'; text += sep + '\n'; text += ' DETAILED FINDINGS\n'; text += sep + '\n\n'; for (var d = 0; d < findings.length; d++) { var fi = findings[d]; text += '─'.repeat(72) + '\n'; text += fi.id + ': ' + fi.title + '\n'; text += '─'.repeat(72) + '\n'; text += 'Severity: ' + fi.severity + ' (CVSS ' + fi.cvssScore.toFixed(1) + ')\n'; text += 'CVSS Vector: ' + fi.cvssVector + '\n'; text += 'Affected: ' + fi.affected + '\n'; text += 'Component: ' + fi.component + '\n'; if (fi.cwe) text += 'CWE: ' + fi.cwe + '\n'; if (fi.mitre) text += 'ATT&CK: ' + fi.mitre + '\n'; text += 'Status: ' + fi.status + '\n\n'; text += 'DESCRIPTION:\n' + fi.description + '\n\n'; if (fi.steps) text += 'STEPS TO REPRODUCE:\n' + fi.steps + '\n\n'; if (fi.evidence) text += 'EVIDENCE:\n' + fi.evidence + '\n\n'; text += 'REMEDIATION:\n' + fi.remediation + '\n\n'; } var blob = new Blob([text], { type: 'text/plain' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = 'pentest-report-' + (eng.engagementId || 'export') + '.txt'; a.click(); URL.revokeObjectURL(url); rtgNotify('Report exported as text file'); }; // ── Remediation Tracker ── function rtgUpdateRemediation() { if (rtgState.findings.length === 0) return; var findings = rtgState.findings; var total = findings.length; var statusCounts = { Open: 0, Remediated: 0, 'Accepted Risk': 0, 'In Progress': 0 }; for (var f = 0; f < findings.length; f++) { if (statusCounts.hasOwnProperty(findings[f].status)) { statusCounts[findings[f].status]++; } } var remediated = statusCounts['Remediated'] || 0; var pct = total > 0 ? Math.round((remediated / total) * 100) : 0; // Stats var statsHtml = '
' + '
' + (statusCounts['Open'] || 0) + '
Open
' + '
' + (statusCounts['In Progress'] || 0) + '
In Progress
' + '
' + remediated + '
Remediated
' + '
' + (statusCounts['Accepted Risk'] || 0) + '
Accepted Risk
' + '
'; document.getElementById('rtg-remediation-stats').innerHTML = statsHtml; // Progress Bar var progHtml = '
' + '
' + pct + '%
' + '' + remediated + ' / ' + total + ' remediated' + '
'; document.getElementById('rtg-remediation-progress').innerHTML = progHtml; // Table var tableHtml = '
' + ''; var sorted = findings.slice().sort(function(a, b) { return b.cvssScore - a.cvssScore; }); for (var s = 0; s < sorted.length; s++) { var fi = sorted[s]; var origIdx = rtgState.findings.indexOf(fi); var sevC = fi.severity.toLowerCase(); var stC = fi.status.toLowerCase().replace(/\s+/g, '-'); tableHtml += '' + '' + '' + '' + '' + '' + '' + '' + ''; } tableHtml += '
IDFindingSeverityStatusOwnerDue DateActions
' + fi.id + '' + fi.title + '' + fi.severity + '' + fi.status + '' + (fi.owner || '--') + '' + (fi.dueDate || '--') + '' + '' + '
'; document.getElementById('rtg-remediation-table').innerHTML = tableHtml; } window.rtgUpdateStatus = function(idx, newStatus) { rtgState.findings[idx].status = newStatus; rtgUpdateRemediation(); rtgRenderFindings(); rtgNotify('Status updated to "' + newStatus + '"'); }; // ── Tab switch hook to refresh remediation ── var origSwitchTab = window.rtgSwitchTab; window.rtgSwitchTab = function(tabId) { origSwitchTab(tabId); if (tabId === 'remediation') rtgUpdateRemediation(); }; // ── Initialize ── rtgCalcCVSS(); })();