| name | pentesting-checklist-platform |
| description | Interactive security assessment checklist covering 23 platforms with 1,000+ checks for pentesting, bug bounty, and security audits |
| triggers | ["how do I use the pentesting checklist tool","show me security assessment checklist platforms","help me track penetration testing progress","how to export pentesting findings","search security checks across platforms","use m14r41 pentesting checklist","organize security assessment workflow","track vulnerability assessment progress"] |
PentestingChecklist Platform Skill
Skill by ara.so — Security Skills collection.
Overview
PentestingChecklist is a comprehensive, interactive security assessment tool that provides structured checklists across 23 platforms including Web, API, Mobile, Cloud, Active Directory, Kubernetes, LLM, and more. Built with TypeScript and React, it runs entirely client-side with no backend, storing all data in localStorage for privacy.
Key Features:
- 1,000+ security checks across 23 platforms
- Hierarchical organization (Platform → Category → Technology → Check)
- Progress tracking and status management (Open/Closed/N/A)
- Per-check notes and evidence recording
- Severity filtering (Critical to Info)
- Global search across all content
- Export to Markdown, CSV, Excel, JSON
- Import/export for assessment continuity
Live Tool: https://checklist.m14r41.in/
Installation & Setup
Local Development
git clone https://github.com/m14r41/PentestingChecklist.git
cd PentestingChecklist
npm install
npm run dev
npm run build
npm run preview
Using the Hosted Version
No installation required — navigate to https://checklist.m14r41.in/ in your browser. All data persists in browser localStorage.
Architecture & Code Structure
Key TypeScript Interfaces
interface Check {
id: string;
title: string;
description: string;
severity: 'critical' | 'high' | 'medium' | 'low' | 'info';
tags: string[];
tools?: string[];
references?: string[];
status?: 'open' | 'closed' | 'na';
notes?: string;
}
interface Technology {
id: string;
name: string;
checks: Check[];
}
interface Category {
id: string;
name: string;
technologies: Technology[];
}
interface Platform {
id: string;
name: string;
description: string;
categories: Category[];
}
interface AssessmentProgress {
platformId: string;
totalChecks: number;
completedChecks: number;
percentage: number;
statusBreakdown: {
open: number;
closed: number;
na: number;
unchecked: number;
};
}
LocalStorage Schema
const STORAGE_KEYS = {
CHECKLIST_STATE: 'pentesting-checklist-state',
USER_NOTES: 'pentesting-checklist-notes',
PROGRESS: 'pentesting-checklist-progress',
COLLAPSED_SECTIONS: 'pentesting-checklist-collapsed'
};
function loadProgress(): Map<string, AssessmentProgress> {
const stored = localStorage.getItem(STORAGE_KEYS.PROGRESS);
return stored ? new Map(JSON.parse(stored)) : new Map();
}
function updateCheckStatus(
platformId: string,
categoryId: string,
techId: string,
checkId: string,
status: 'open' | 'closed' | 'na'
): void {
const key = `${platformId}.${categoryId}.${techId}.${checkId}`;
const state = JSON.parse(localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE) || '{}');
state[key] = { ...state[key], status };
localStorage.setItem(STORAGE_KEYS.CHECKLIST_STATE, JSON.stringify(state));
}
Using the Checklist
Navigation Patterns
const platformUrls = {
allPlatforms: '/checklist',
web: '/web',
api: '/api',
mobile: '/mobile',
cloud: '/cloud',
activeDirectory: '/active-directory',
kubernetes: '/kubernetes',
llm: '/llm-security',
mcp: '/mcp-security'
};
function navigateToPlatform(platformId: string) {
window.location.href = `/${platformId}`;
}
Search Functionality
The global search (⌘K / Ctrl+K) searches across:
- Platform names
- Category names
- Technology names
- Check titles and descriptions
- Tags
- Tools
- References
interface SearchResult {
type: 'platform' | 'category' | 'technology' | 'check';
platformId: string;
categoryId?: string;
technologyId?: string;
checkId?: string;
title: string;
description?: string;
path: string;
}
function performSearch(query: string, platforms: Platform[]): SearchResult[] {
const results: SearchResult[] = [];
const lowerQuery = query.toLowerCase();
platforms.forEach(platform => {
platform.categories.forEach(category => {
category.technologies.forEach(tech => {
tech.checks.forEach(check => {
if (
check.title.toLowerCase().includes(lowerQuery) ||
check.description.toLowerCase().includes(lowerQuery) ||
check.tags.some(tag => tag.toLowerCase().includes(lowerQuery))
) {
results.push({
type: 'check',
platformId: platform.id,
categoryId: category.id,
technologyId: tech.id,
checkId: check.id,
title: check.title,
description: check.description,
path: `/${platform.id}#${check.id}`
});
}
});
});
});
});
return results;
}
Working with Assessment Data
Adding Notes to Checks
interface CheckNote {
checkId: string;
content: string;
timestamp: number;
findings?: string[];
screenshots?: string[];
}
function saveCheckNote(
platformId: string,
categoryId: string,
techId: string,
checkId: string,
note: string
): void {
const key = `${platformId}.${categoryId}.${techId}.${checkId}`;
const notes = JSON.parse(localStorage.getItem(STORAGE_KEYS.USER_NOTES) || '{}');
notes[key] = {
checkId,
content: note,
timestamp: Date.now(),
findings: []
};
localStorage.setItem(STORAGE_KEYS.USER_NOTES, JSON.stringify(notes));
}
function getCheckNote(checkKey: string): CheckNote | null {
const notes = JSON.parse(localStorage.getItem(STORAGE_KEYS.USER_NOTES) || '{}');
return notes[checkKey] || null;
}
Progress Calculation
function calculatePlatformProgress(platform: Platform): AssessmentProgress {
let totalChecks = 0;
let completedChecks = 0;
const statusBreakdown = { open: 0, closed: 0, na: 0, unchecked: 0 };
const state = JSON.parse(localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE) || '{}');
platform.categories.forEach(category => {
category.technologies.forEach(tech => {
tech.checks.forEach(check => {
totalChecks++;
const key = `${platform.id}.${category.id}.${tech.id}.${check.id}`;
const checkState = state[key];
if (checkState?.status) {
completedChecks++;
statusBreakdown[checkState.status]++;
} else {
statusBreakdown.unchecked++;
}
});
});
});
return {
platformId: platform.id,
totalChecks,
completedChecks,
percentage: Math.round((completedChecks / totalChecks) * 100),
statusBreakdown
};
}
Export Functionality
Export to JSON
interface ExportData {
version: string;
exportDate: string;
platforms: {
[platformId: string]: {
checks: {
[checkId: string]: {
status: 'open' | 'closed' | 'na';
notes: string;
timestamp: number;
};
};
};
};
}
function exportToJSON(): string {
const state = JSON.parse(localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE) || '{}');
const notes = JSON.parse(localStorage.getItem(STORAGE_KEYS.USER_NOTES) || '{}');
const exportData: ExportData = {
version: '1.0',
exportDate: new Date().toISOString(),
platforms: {}
};
Object.keys(state).forEach(key => {
const [platformId, categoryId, techId, checkId] = key.split('.');
if (!exportData.platforms[platformId]) {
exportData.platforms[platformId] = { checks: {} };
}
exportData.platforms[platformId].checks[checkId] = {
status: state[key].status,
notes: notes[key]?.content || '',
timestamp: notes[key]?.timestamp || Date.now()
};
});
return JSON.stringify(exportData, null, 2);
}
Export to Markdown
function exportToMarkdown(platform: Platform, includeOnlyOpen = false): string {
let markdown = `# ${platform.name} Security Assessment\n\n`;
markdown += `**Export Date:** ${new Date().toLocaleDateString()}\n\n`;
const state = JSON.parse(localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE) || '{}');
const notes = JSON.parse(localStorage.getItem(STORAGE_KEYS.USER_NOTES) || '{}');
platform.categories.forEach(category => {
markdown += `## ${category.name}\n\n`;
category.technologies.forEach(tech => {
markdown += `### ${tech.name}\n\n`;
tech.checks.forEach(check => {
const key = `${platform.id}.${category.id}.${tech.id}.${check.id}`;
const checkState = state[key];
if (includeOnlyOpen && checkState?.status !== 'open') {
return;
}
markdown += `#### ${check.title}\n\n`;
markdown += `**Severity:** ${check.severity.toUpperCase()}\n\n`;
markdown += `**Status:** ${checkState?.status || 'Unchecked'}\n\n`;
markdown += `**Description:** ${check.description}\n\n`;
if (notes[key]?.content) {
markdown += `**Notes:**\n\n${notes[key].content}\n\n`;
}
if (check.tools && check.tools.length > 0) {
markdown += `**Tools:** ${check.tools.join(', ')}\n\n`;
}
markdown += '---\n\n';
});
});
});
return markdown;
}
Export to CSV
function exportToCSV(platform: Platform): string {
const headers = [
'Platform',
'Category',
'Technology',
'Check',
'Severity',
'Status',
'Notes',
'Tags',
'Tools'
];
let csv = headers.join(',') + '\n';
const state = JSON.parse(localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE) || '{}');
const notes = JSON.parse(localStorage.getItem(STORAGE_KEYS.USER_NOTES) || '{}');
platform.categories.forEach(category => {
category.technologies.forEach(tech => {
tech.checks.forEach(check => {
const key = `${platform.id}.${category.id}.${tech.id}.${check.id}`;
const checkState = state[key];
const checkNotes = notes[key]?.content || '';
const row = [
platform.name,
category.name,
tech.name,
`"${check.title}"`,
check.severity,
checkState?.status || 'unchecked',
`"${checkNotes.replace(/"/g, '""')}"`,
`"${check.tags.join('; ')}"`,
`"${(check.tools || []).join('; ')}"`
];
csv += row.join(',') + '\n';
});
});
});
return csv;
}
Import Functionality
function importFromJSON(jsonString: string): void {
try {
const importData: ExportData = JSON.parse(jsonString);
if (importData.version !== '1.0') {
throw new Error('Unsupported export version');
}
const currentState = JSON.parse(localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE) || '{}');
const currentNotes = JSON.parse(localStorage.getItem(STORAGE_KEYS.USER_NOTES) || '{}');
Object.entries(importData.platforms).forEach(([platformId, platformData]) => {
Object.entries(platformData.checks).forEach(([checkId, checkData]) => {
const key = checkId;
currentState[key] = {
status: checkData.status,
timestamp: checkData.timestamp
};
if (checkData.notes) {
currentNotes[key] = {
checkId,
content: checkData.notes,
timestamp: checkData.timestamp
};
}
});
});
localStorage.setItem(STORAGE_KEYS.CHECKLIST_STATE, JSON.stringify(currentState));
localStorage.setItem(STORAGE_KEYS.USER_NOTES, JSON.stringify(currentNotes));
console.log('Import successful');
} catch (error) {
console.error('Import failed:', error);
throw error;
}
}
Common Workflows
Starting a New Assessment
function startWebAssessment() {
window.location.href = '/web';
}
function expandAllCategories() {
const collapsed = new Set();
localStorage.setItem(STORAGE_KEYS.COLLAPSED_SECTIONS, JSON.stringify([...collapsed]));
}
function filterBySeverity(minSeverity: 'critical' | 'high' | 'medium' | 'low') {
const severityLevels = ['critical', 'high', 'medium', 'low', 'info'];
const minIndex = severityLevels.indexOf(minSeverity);
}
Recording Findings
interface Finding {
checkId: string;
vulnerability: string;
impact: string;
steps: string[];
payload?: string;
evidence: string[];
remediation: string;
}
function recordFinding(
platformId: string,
categoryId: string,
techId: string,
checkId: string,
finding: Finding
): void {
updateCheckStatus(platformId, categoryId, techId, checkId, 'open');
const noteContent = `
**Vulnerability:** ${finding.vulnerability}
**Impact:** ${finding.impact}
**Steps to Reproduce:**
${finding.steps.map((step, i) => `${i + 1}. ${step}`).join('\n')}
${finding.payload ? `**Payload:**\n\`\`\`\n${finding.payload}\n\`\`\`` : ''}
**Evidence:**
${finding.evidence.map(e => `- ${e}`).join('\n')}
**Remediation:**
${finding.remediation}
`.trim();
saveCheckNote(platformId, categoryId, techId, checkId, noteContent);
}
Filtering Open Findings
function getOpenFindings(platform: Platform): Array<{
check: Check;
category: string;
technology: string;
notes: string;
}> {
const openFindings: Array<any> = [];
const state = JSON.parse(localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE) || '{}');
const notes = JSON.parse(localStorage.getItem(STORAGE_KEYS.USER_NOTES) || '{}');
platform.categories.forEach(category => {
category.technologies.forEach(tech => {
tech.checks.forEach(check => {
const key = `${platform.id}.${category.id}.${tech.id}.${check.id}`;
if (state[key]?.status === 'open') {
openFindings.push({
check,
category: category.name,
technology: tech.name,
notes: notes[key]?.content || ''
});
}
});
});
});
return openFindings;
}
Platform-Specific Patterns
Web Application Assessment
const webAppChecks = {
authentication: [
'Test for username enumeration',
'Check password policy enforcement',
'Verify session timeout settings',
'Test for account lockout mechanisms'
],
authorization: [
'Test horizontal privilege escalation',
'Test vertical privilege escalation',
'Check for IDOR vulnerabilities',
'Verify API endpoint authorization'
],
injection: [
'Test for SQL injection',
'Check for XSS vulnerabilities',
'Test for command injection',
'Verify template injection protections'
]
};
API Security Assessment
const apiSecurityChecks = {
authentication: [
'Test broken object level authorization (BOLA)',
'Verify broken user authentication',
'Check for excessive data exposure',
'Test resource consumption limits'
],
authorization: [
'Test broken function level authorization',
'Verify mass assignment protections',
'Check security misconfiguration',
'Test for SSRF vulnerabilities'
]
};
Cloud Security Assessment
const cloudSecurityChecks = {
iam: [
'Review IAM policies for overprivileged roles',
'Check for unused access keys',
'Verify MFA enforcement',
'Test for privilege escalation paths'
],
storage: [
'Check for publicly accessible S3 buckets',
'Verify encryption at rest',
'Test bucket policy configurations',
'Check for sensitive data exposure'
],
compute: [
'Test instance metadata SSRF',
'Verify security group configurations',
'Check for exposed management interfaces',
'Test network segmentation'
]
};
Troubleshooting
Data Persistence Issues
function isLocalStorageAvailable(): boolean {
try {
const test = '__localStorage_test__';
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch (e) {
return false;
}
}
function resetChecklistData(): void {
if (confirm('This will clear all assessment data. Continue?')) {
localStorage.removeItem(STORAGE_KEYS.CHECKLIST_STATE);
localStorage.removeItem(STORAGE_KEYS.USER_NOTES);
localStorage.removeItem(STORAGE_KEYS.PROGRESS);
localStorage.removeItem(STORAGE_KEYS.COLLAPSED_SECTIONS);
window.location.reload();
}
}
function backupBeforeReset(): void {
const backup = {
state: localStorage.getItem(STORAGE_KEYS.CHECKLIST_STATE),
notes: localStorage.getItem(STORAGE_KEYS.USER_NOTES),
progress: localStorage.getItem(STORAGE_KEYS.PROGRESS)
};
const blob = new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `checklist-backup-${Date.now()}.json`;
a.click();
}
Search Performance
function createDebouncedSearch(delay = 300) {
let timeoutId: number;
return function(query: string, callback: (results: SearchResult[]) => void) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
const results = performSearch(query, getAllPlatforms());
callback(results);
}, delay);
};
}
const debouncedSearch = createDebouncedSearch();
Export Size Limitations
function exportPlatformIndividually(platformId: string): void {
const platform = getPlatformById(platformId);
const markdown = exportToMarkdown(platform);
const blob = new Blob([markdown], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${platformId}-assessment-${Date.now()}.md`;
a.click();
URL.revokeObjectURL(url);
}
Best Practices
- Regular Backups: Export your assessment data regularly, especially before major changes
- Structured Notes: Use consistent formatting in notes for easier report generation
- Severity Filtering: Start with Critical/High severity checks, then work down
- Progress Tracking: Mark checks as N/A when not applicable to keep accurate progress metrics
- Evidence Recording: Include timestamps, URLs, and request/response data in notes
- Export Early: Don't wait until the end — export incremental findings
- Browser Compatibility: Recommended browsers are Chrome, Firefox, or Edge (modern versions)
Integration Patterns
Custom Automation Scripts
function updateFromBurpSuite(findings: Array<{url: string, issue: string}>): void {
findings.forEach(finding => {
const checkMapping = mapBurpIssueToCheck(finding.issue);
if (checkMapping) {
updateCheckStatus(
checkMapping.platformId,
checkMapping.categoryId,
checkMapping.techId,
checkMapping.checkId,
'open'
);
saveCheckNote(
checkMapping.platformId,
checkMapping.categoryId,
checkMapping.techId,
checkMapping.checkId,
`Found by Burp Suite at ${finding.url}: ${finding.issue}`
);
}
});
}
This skill provides comprehensive coverage of the PentestingChecklist platform for AI agents to assist developers and security professionals in conducting structured security assessments.