Skip to main content Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/proffesor-for-testing/agentic-qe --skill n8n-security-testingLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Plus depuis ce dépôt Ruflo is a multi-agent orchestration platform for AI coding agents (Claude Code, Cursor, Codex, Copilot, Gemini, Amp, +12 more). Use this skill when the user wants to (1) install/init ruflo in a project, (2) run multi-agent swarms with hierarchical coordination, (3) use ruflo's 314+ MCP tools for memory, routing, hooks, sub-agents, or workflows, (4) check ruflo status/version/doctor health, or (5) discover which of ruflo's 30+ plugins fits their task.
Build dependency-aware execution plans for complex Agentic QE, Ruflo, integration, migration, or multi-stream engineering programs. Use when Codex must turn research or requirements into phased work, select a small AQE fleet, map critical paths and parallel streams, define acceptance gates, or sequence risky changes. Use aqe-plan-quality instead when the primary output is only a test or quality plan.
Conduct evidence-first technical research for Agentic QE, Ruflo, related ruvnet projects, or external tools. Use when Codex must investigate a repository, compare current upstream changes, trace dependencies and history, distinguish verified facts from inference, or synthesize findings into actionable engineering recommendations. Do not use for a simple known-answer lookup or an implementation-only task.
Métiers associés SOC
Basé sur la classification professionnelle SOC
Explorateur de fichiers
4 fichiers name n8n-security-testing description Credential exposure detection, OAuth flow validation, API key management testing, and data sanitization verification for n8n workflows. Use when validating n8n workflow security. category n8n-testing priority critical tokenEstimate 1100 agents ["n8n-integration-test"] implementation_status production optimization_version 1 last_optimized "2025-12-15T00:00:00.000Z" dependencies [] quick_reference_card true tags ["n8n","security","credentials","oauth","api-keys","encryption","testing"] trust_tier 3 validation {"schema_path":"schemas/output.json","validator_path":"scripts/validate-config.json","eval_path":"evals/n8n-security-testing.yaml"}
n8n Security Testing
<default_to_action>
When testing n8n security:
SCAN for credential exposure in workflows
VERIFY encryption of sensitive data
TEST OAuth token handling
CHECK for insecure data transmission
VALIDATE input sanitization
Quick Security Checklist:
No credentials in workflow JSON
No credentials in execution logs
OAuth tokens properly encrypted
API keys not in version control
Webhook authentication enabled
Input data sanitized
Critical Success Factors:
Scan all workflow exports
Test credential rotation
Verify encryption at rest
Check audit logging
</default_to_action>
Quick Reference Card
Security Risk Areas
Area Risk Level Testing Focus Credential Storage Critical Encryption, exposure Webhook Security High Authentication, validation Expression Injection High Input sanitization Data Leakage Medium Logging, error messages OAuth Flows Medium Token handling, refresh
Credential Types
Type Exposure Risk Rotation API Keys High if exposed Manual OAuth Tokens Medium (short-lived) Automatic Passwords Critical Manual Webhooks Medium Generate new
Credential Security Testing
Scan for Exposed Credentials
async ( ): < > {
workflow = (workflowId);
workflowJson = . (workflow, , );
sensitivePatterns = [
{ : , : },
{ : , : },
{ : , : },
{ : , : },
{ : , : },
{ : , : },
{ : , : },
{ : , : },
{ : , : },
{ : , : }
];
: [] = [];
( pattern sensitivePatterns) {
matches = workflowJson. (pattern. );
(matches) {
( match matches) {
findings. ({
: pattern. ,
: (workflow, match),
: ,
:
});
}
}
}
{
workflowId,
: ,
: findings. ,
findings,
: findings. ===
};
}
function
scanForExposedCredentials
workflowId : string
Promise
CredentialScanResult
const
await
getWorkflow
const
JSON
stringify
null
2
const
name
'Generic API Key'
pattern
/api[_-]?key["\s:=]+["']?([a-zA-Z0-9_-]{20,})["']?/gi
name
'AWS Access Key'
pattern
/AKIA[0-9A-Z]{16}/g
name
'AWS Secret Key'
pattern
/[a-zA-Z0-9/+=]{40}/g
name
'Bearer Token'
pattern
/bearer\s+[a-zA-Z0-9_-]{20,}/gi
name
'JWT Token'
pattern
/eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*/g
name
'Slack Token'
pattern
/xox[baprs]-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24}/g
name
'Password Field'
pattern
/"password":\s*"[^"]+"/gi
name
'Secret Field'
pattern
/"secret":\s*"[^"]+"/gi
name
'Client Secret'
pattern
/client[_-]?secret["\s:=]+["']?([a-zA-Z0-9_-]{20,})["']?/gi
name
'Refresh Token'
pattern
/refresh[_-]?token["\s:=]+["']?([a-zA-Z0-9_-]{20,})["']?/gi
const
findings
CredentialFinding
for
const
of
const
match
pattern
if
for
const
of
push
type
name
location
findLocationInWorkflow
severity
'CRITICAL'
recommendation
`Remove ${pattern.name} from workflow. Use n8n credentials instead.`
return
scanned
true
findingsCount
length
secure
length
0
Verify Credential Encryption
async function verifyCredentialEncryption (credentialId : string ): Promise <EncryptionResult > {
const credential = await getCredentialMetadata (credentialId);
const encryptionChecks = {
isEncrypted : !isPlainText (credential.data ),
algorithm : credential.encryptionAlgorithm || 'unknown' ,
keyDerivation : credential.keyDerivation || 'unknown' ,
instanceEncryption : credential.useInstanceKey || false
};
return {
credentialId,
credentialName : credential.name ,
credentialType : credential.type ,
encryption : encryptionChecks,
secure : encryptionChecks.isEncrypted && encryptionChecks.algorithm !== 'unknown' ,
recommendations : generateEncryptionRecommendations (encryptionChecks)
};
}
function isPlainText (data : string ): boolean {
const plainTextPatterns = [
/^[a-zA-Z0-9_-]+$/ ,
/^sk-[a-zA-Z0-9]+$/ ,
/^Bearer\s/ ,
];
return plainTextPatterns.some (p => p.test (data));
}
Test Credential Rotation
async function testCredentialRotation (credentialId : string ): Promise <RotationTestResult > {
const credential = await getCredentialMetadata (credentialId);
const rotationTests = {
hasRotationSchedule : !!credential.rotationSchedule ,
lastRotated : credential.lastRotatedAt ,
rotationDue : isRotationDue (credential),
oauthRefresh : credential.type .includes ('oauth' )
? await testOAuthRefresh (credentialId)
: null ,
credentialAge : calculateAge (credential.createdAt ),
isStale : calculateAge (credential.createdAt ) > 90
};
return {
credentialId,
rotationTests,
recommendations : generateRotationRecommendations (rotationTests)
};
}
async function testOAuthRefresh (credentialId : string ): Promise <OAuthRefreshResult > {
try {
const refreshed = await refreshCredential (credentialId);
return {
success : true ,
newExpiry : refreshed.expiresAt ,
refreshedAt : new Date ()
};
} catch (error) {
return {
success : false ,
error : error.message ,
recommendation : 'Re-authorize OAuth connection'
};
}
}
Webhook Security Testing
Authentication Testing
async function testWebhookAuthentication (webhookUrl : string ): Promise <WebhookAuthResult > {
const authTests = [
{
name : 'No Auth' ,
headers : {},
expectedStatus : 401
},
{
name : 'Invalid Basic Auth' ,
headers : { 'Authorization' : 'Basic aW52YWxpZDppbnZhbGlk' },
expectedStatus : 401
},
{
name : 'Invalid Bearer' ,
headers : { 'Authorization' : 'Bearer invalid-token-12345' },
expectedStatus : 401
},
{
name : 'Invalid Header Auth' ,
headers : { 'X-API-Key' : 'invalid-key' },
expectedStatus : 401
}
];
const results : AuthTestResult [] = [];
for (const test of authTests) {
const response = await fetch (webhookUrl, {
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
...test.headers
},
body : '{}'
});
results.push ({
test : test.name ,
status : response.status ,
passed : response.status === test.expectedStatus ,
actualStatus : response.status ,
expectedStatus : test.expectedStatus
});
}
const noAuthResponse = results.find (r => r.test === 'No Auth' );
const webhookHasAuth = noAuthResponse?.status === 401 ;
return {
webhookUrl,
hasAuthentication : webhookHasAuth,
testResults : results,
allTestsPassed : results.every (r => r.passed ),
recommendation : !webhookHasAuth
? 'CRITICAL: Enable authentication on webhook'
: null
};
}
Input Validation Testing
async function testWebhookInputValidation (webhookUrl : string ): Promise <InputValidationResult > {
const maliciousPayloads = [
{
name : 'XSS Script Tag' ,
payload : { text : '<script>alert("xss")</script>' },
check : 'sanitized'
},
{
name : 'XSS Event Handler' ,
payload : { text : '<img onerror="alert(1)" src="x">' },
check : 'sanitized'
},
{
name : 'SQL Injection' ,
payload : { id : "1; DROP TABLE users; --" },
check : 'escaped'
},
{
name : 'Command Injection' ,
payload : { filename : '; rm -rf /' },
check : 'rejected'
},
{
name : 'Path Traversal' ,
payload : { path : '../../../etc/passwd' },
check : 'rejected'
},
{
name : 'JSON Injection' ,
payload : { data : '{"admin": true}' },
check : 'escaped'
},
{
name : 'Oversized Payload' ,
payload : { data : 'x' .repeat (10000000 ) },
check : 'rejected'
}
];
const results : ValidationTestResult [] = [];
for (const test of maliciousPayloads) {
try {
const response = await fetch (webhookUrl, {
method : 'POST' ,
headers : { 'Content-Type' : 'application/json' },
body : JSON .stringify (test.payload )
});
const responseBody = await response.text ();
results.push ({
test : test.name ,
status : response.status ,
handled : response.status !== 500 ,
sanitized : !responseBody.includes (test.payload .text || test.payload .data ),
recommendation : response.status === 500
? `Input not handled safely: ${test.name} `
: null
});
} catch (error) {
results.push ({
test : test.name ,
handled : false ,
error : error.message
});
}
}
return {
webhookUrl,
testsRun : maliciousPayloads.length ,
passed : results.filter (r => r.handled ).length ,
failed : results.filter (r => !r.handled ).length ,
results,
secure : results.every (r => r.handled )
};
}
Expression Security Testing
Detect Dangerous Expressions
async function scanExpressionsForSecurity (workflowId : string ): Promise <ExpressionSecurityResult > {
const workflow = await getWorkflow (workflowId);
const expressions = extractExpressions (workflow);
const dangerousPatterns = [
{ name : 'eval()' , pattern : /eval\s*\(/g , severity : 'CRITICAL' },
{ name : 'Function()' , pattern : /new\s+Function\s*\(/g , severity : 'CRITICAL' },
{ name : 'setTimeout string' , pattern : /setTimeout\s*\(\s*["'`]/g , severity : 'HIGH' },
{ name : 'setInterval string' , pattern : /setInterval\s*\(\s*["'`]/g , severity : 'HIGH' },
{ name : 'require()' , pattern : /require\s*\(/g , severity : 'HIGH' },
{ name : 'import()' , pattern : /import\s*\(/g , severity : 'HIGH' },
{ name : 'fs access' , pattern : /\bfs\./g , severity : 'HIGH' },
{ name : 'child_process' , pattern : /child_process/g , severity : 'CRITICAL' },
{ name : 'process.' , pattern : /process\./g , severity : 'MEDIUM' },
{ name : 'exec()' , pattern : /exec\s*\(/g , severity : 'CRITICAL' },
{ name : 'spawn()' , pattern : /spawn\s*\(/g , severity : 'CRITICAL' },
{ name : 'fetch()' , pattern : /fetch\s*\(/g , severity : 'MEDIUM' },
{ name : 'XMLHttpRequest' , pattern : /XMLHttpRequest/g , severity : 'MEDIUM' },
{ name : '__proto__' , pattern : /__proto__/g , severity : 'HIGH' },
{ name : 'constructor.prototype' , pattern : /constructor\.prototype/g , severity : 'HIGH' }
];
const findings : SecurityFinding [] = [];
for (const expr of expressions) {
for (const pattern of dangerousPatterns) {
if (pattern.pattern .test (expr.expression )) {
findings.push ({
node : expr.nodeName ,
parameter : expr.parameter ,
expression : expr.expression ,
pattern : pattern.name ,
severity : pattern.severity ,
recommendation : `Remove ${pattern.name} from expression. Use safer alternatives.`
});
}
}
}
return {
workflowId,
expressionsScanned : expressions.length ,
findings,
secure : findings.length === 0 ,
criticalIssues : findings.filter (f => f.severity === 'CRITICAL' ).length ,
highIssues : findings.filter (f => f.severity === 'HIGH' ).length
};
}
Data Leakage Testing
Scan Execution Logs
async function scanExecutionLogs (workflowId : string , executionCount : number = 10 ): Promise <LogScanResult > {
const executions = await getRecentExecutions (workflowId, executionCount);
const findings : LogFinding [] = [];
const sensitivePatterns = [
{ name : 'Password' , pattern : /password["\s:=]+["']?[^"'\s]+["']?/gi },
{ name : 'API Key' , pattern : /api[_-]?key["\s:=]+["']?[^"'\s]{20,}["']?/gi },
{ name : 'Token' , pattern : /token["\s:=]+["']?[a-zA-Z0-9_-]{20,}["']?/gi },
{ name : 'Secret' , pattern : /secret["\s:=]+["']?[^"'\s]+["']?/gi },
{ name : 'Authorization Header' , pattern : /authorization["\s:]+["']?(bearer|basic)\s+[^"'\s]+["']?/gi }
];
for (const execution of executions) {
const logString = JSON .stringify (execution.data , null , 2 );
for (const pattern of sensitivePatterns) {
const matches = logString.match (pattern.pattern );
if (matches) {
findings.push ({
executionId : execution.id ,
type : pattern.name ,
matchCount : matches.length ,
severity : 'HIGH' ,
recommendation : `Mask ${pattern.name} in logs`
});
}
}
}
return {
workflowId,
executionsScanned : executions.length ,
findings,
secure : findings.length === 0 ,
recommendation : findings.length > 0
? 'Enable credential masking in n8n settings'
: null
};
}
Check Error Message Exposure
async function checkErrorMessageSecurity (workflowId : string ): Promise <ErrorMessageResult > {
const errorScenarios = [
{ name : 'Invalid credentials' , inject : { credentials : null } },
{ name : 'Invalid endpoint' , inject : { url : 'https://invalid' } },
{ name : 'Database error' , inject : { query : 'INVALID SQL' } }
];
const findings : ErrorFinding [] = [];
for (const scenario of errorScenarios) {
try {
await executeWithError (workflowId, scenario.inject );
} catch (error) {
const errorMessage = error.message ;
const sensitiveData = [
{ name : 'Connection string' , pattern : /mongodb:\/\/[^@]+@/i },
{ name : 'Password in URL' , pattern : /:\/\/[^:]+:[^@]+@/i },
{ name : 'Full file path' , pattern : /\/(?:home|Users|var)\/[^\s]+/i },
{ name : 'Stack trace' , pattern : /at\s+\w+\s+\([^)]+\)/i },
{ name : 'Internal IP' , pattern : /\b(?:10|172\.(?:1[6-9]|2[0-9]|3[01])|192\.168)\.\d+\.\d+\b/i }
];
for (const check of sensitiveData) {
if (check.pattern .test (errorMessage)) {
findings.push ({
scenario : scenario.name ,
exposedData : check.name ,
severity : 'MEDIUM' ,
recommendation : `Sanitize ${check.name} from error messages`
});
}
}
}
}
return {
workflowId,
scenariosTested : errorScenarios.length ,
findings,
secure : findings.length === 0
};
}
Security Report Template # n8n Security Audit Report
## Summary
| Category | Status | Findings |
|----------|--------|----------|
| Credential Security | PASS/FAIL | X issues |
| Webhook Security | PASS/FAIL | X issues |
| Expression Security | PASS/FAIL | X issues |
| Data Leakage | PASS/FAIL | X issues |
## Critical Findings
### CRIT-001: API Key Exposed in Workflow
- **Location:** HTTP Request node, URL parameter
- **Impact:** Credential theft, unauthorized access
- **Fix:** Move to n8n credentials store
### CRIT-002: eval() in Expression
- **Location:** Set node, custom field
- **Impact:** Remote code execution
- **Fix:** Remove eval, use explicit logic
## Recommendations
1. **Enable webhook authentication** - All public webhooks
2. **Rotate exposed credentials** - Immediately
3. **Enable log masking** - For all credentials
4. **Regular security scans** - Weekly automated scans
## Compliance Status
- OWASP Top 10: X/10 addressed
- SOC 2: Partially compliant
- GDPR: Review data handling
Related Skills
Remember n8n handles sensitive credentials for 400+ integrations. Security testing requires:
Credential exposure scanning
Encryption verification
Webhook authentication testing
Expression security analysis
Data leakage detection
Critical practices: Never expose credentials in workflow JSON. Enable webhook authentication. Mask sensitive data in logs. Rotate credentials regularly. Scan expressions for dangerous functions.