Writeups

Writeup

๐Ÿง… Peelr: Peel back every secret!

Peelr is a fast JavaScript security scanner for bug bounty hunters and security researchers. Point it at a .js file and it highlights the lines worth opening first: exposed secrets, dangerous sinks, prototype pollution gadgets, GraphQL clues, and source-to-sink taint flows.

Why Peelr#

Modern targets ship huge bundles, vendor blobs, and frontend code paths nobody wants to read line by line. Peelr cuts that down by combining regex-based detection with lightweight token-level flow correlation, confidence scoring, and per-file risk scoring.

It is designed for:

  • Bug bounty recon
  • Web app security reviews
  • Triage during content discovery
  • Repeat scans against changing targets
  • Fast CLI pipelines with minimal setup

It is not trying to be a full static analysis framework. It is trying to be fast, useful, and easy to drop into real recon.


What It Finds#

  • Hardcoded API keys, tokens, passwords, private keys, and connection strings
  • XSS sinks such as innerHTML, eval, document.write, Function(), and dangerouslySetInnerHTML
  • Source-to-sink taint flows like location.hash -> innerHTML
  • Prototype pollution gadgets like __proto__, constructor.prototype, and unsafe merge patterns
  • GraphQL endpoints, operations, Apollo usage, and introspection fields
  • Endpoints, API paths, emails, filesystem paths, S3 references, and developer comments
  • A 0-100 risk score for each scanned file
  • Diffs against previous scans so target changes stand out immediately

Quick Example#

 ____           _
|  _ \ ___  ___| |_ __
| |_) / _ \/ _ \ | '__|
|  __/  __/  __/ | |
|_|   \___|\___|_|_|
Peel back every secret. v1.1.0

  scanning https://target.com/app.js

https://target.com/app.js
1842 lines ยท 7 findings ยท 2 flows ยท risk HIGH [68/100]
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โšก SOURCE โ†’ SINK FLOWS
  location.hash โ†’ innerHTML  via var 'userInput'  (L12โ†’L47)
    # Direct HTML injection. Tainted variable reaches innerHTML.
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
SEV       CONF    CATEGORY               TYPE                            VALUE
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
CRITICAL  high    api_keys               AWS Access Key                  AKIAIOSFODNN7EXAMPLE
HIGH      high    api_keys               GitHub Token (PAT)             ghp_aBcDeFgHiJkLmN...
HIGH      medium  xss                    innerHTML assignment           .innerHTML =
HIGH      high    prototype_pollution    __proto__ bracket write        .__proto__[
MEDIUM    high    graphql                GraphQL introspection field    __schema

CLI


What Peelr Is And Isn’t#

Peelr doesPeelr does not
Fast pattern matching over real-world JSFull SSA or inter-procedural dataflow
Lightweight source-to-sink flow correlationProve exploitability
Confidence scoring to reduce noiseReplace manual validation
Historical diffing for repeat scansAct like a browser crawler
Clean CLI and web UI workflowsRequire a heavy dependency stack

Installation#

Requirement: Go 1.21+

# Arch
sudo pacman -S go

# Kali / Debian / Ubuntu
sudo apt install golang-go

# macOS
brew install go

Build from source:

git clone https://github.com/ibfavas/peelr.git
cd peelr
go build -o peelr ./cmd/peelr/

Peelr uses the Go standard library only. No external runtime dependencies and no extra build tooling.


Usage#

Web UI#

./peelr
./peelr --port 9000

Then open http://localhost:8080 or your chosen port.

Dashboard Scan Results

The web UI includes:

  • Risk score per file
  • Taint flow viewer
  • Diff mode
  • Severity and category filtering
  • JSON export
  • Batch analysis for up to 50 URLs

CLI: single URL#

./peelr --url https://target.com/app.js

CLI: pipe from recon tools#

gau target.com | grep '\.js$' | ./peelr
waybackurls target.com | grep '\.js$' | ./peelr
katana -u target.com -f endpoint | grep '\.js$' | ./peelr

CLI: file input#

./peelr --file js_urls.txt --workers 10

Output formats#

# Default table output
./peelr --url https://target.com/app.js

# JSON
./peelr --url https://target.com/app.js --format json

# Plain tab-separated output
./peelr --url https://target.com/app.js --format plain

Filtering#

./peelr --url https://target.com/app.js --only-high-conf
./peelr --url https://target.com/app.js --min-severity high
./peelr --url https://target.com/app.js --min-confidence high --min-severity medium
./peelr --file urls.txt --no-flows

Diff and history#

# First run creates history
./peelr --url https://target.com/app.js

# Compare against the previous scan
./peelr --url https://target.com/app.js --diff

# Show scan history
./peelr --history

# Clear stored history
./peelr --clear-history

Exit codes for automation#

Peelr exits with code 1 when filtered results contain any high or critical finding.

./peelr --url https://deploy.example.com/app.js --only-high-conf
echo $?

Silent mode#

./peelr --url https://target.com/app.js --silent --format plain

Detection Coverage#

CategoryExamples
API keys and tokensAWS, Google, GitHub, Stripe, Slack, Firebase, JWT, Twilio, SendGrid, Shopify, PayPal, Square, Mapbox
CredentialsHardcoded passwords, Basic auth headers, bearer tokens, DB connection strings, private key blocks
XSS sinksinnerHTML, outerHTML, eval(), document.write(), Function(), dangerouslySetInnerHTML, jQuery .html(), insertAdjacentHTML
DOM sinkspostMessage, srcdoc, document.domain, dynamic script.src, window.location
Prototype pollution__proto__, constructor.prototype, unsafe merges, lodash merge patterns
GraphQLEndpoints, operations, Apollo client usage, gql tags, introspection fields
Endpoints and URLsfetch(), axios, XHR, jQuery AJAX, API literals, full URLs
MiscEmails, Unix and Windows paths, S3 bucket references, TODO/FIXME/security comments

Tracked taint sources#

location.hash, location.search, location.href, document.URL, document.referrer, document.cookie, URLSearchParams, postMessage event.data, window.name, localStorage.getItem, req.body, req.params, req.query, JSON.parse(input)

Tracked taint sinks#

innerHTML, outerHTML, document.write, eval, Function(), insertAdjacentHTML, jQuery .html(), setTimeout(string), script.src, window.location, postMessage


Confidence Model#

Each finding gets a confidence level:

ConfidenceMeaning
highStrong structural match with low expected false positives
mediumPlausible finding that needs manual confirmation
lowBroad heuristic; expect more noise

Confidence is automatically downgraded when the value looks like a placeholder such as example, dummy, or REPLACE, or when the match appears on a comment line.


Risk Scoring#

Each file gets a 0-100 score based on severity, confidence, and confirmed taint flows.

ScoreLabel
80-100critical
55-79high
30-54medium
10-29low
0-9minimal

CLI output is sorted by risk so the worst files rise to the top first.


HTTP API#

Analyze one JS file#

curl -X POST http://localhost:8080/api/analyze \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://target.com/app.js"}' | jq .

Analyze a batch#

curl -X POST http://localhost:8080/api/analyze/batch \
  -H 'Content-Type: application/json' \
  -d '{"urls":["https://target.com/app.js","https://target.com/vendor.js"]}' | jq .

Retrieve history#

curl http://localhost:8080/api/history | jq .

Batch API limits: 1-50 URLs per request.


CLI Flags#

FlagDefaultDescription
--port8080Web UI port
--url-Single URL to analyze
--file-File with one URL per line
--formattableOutput: table, json, plain
--min-severity-critical, high, medium, low, info
--min-confidence-high, medium, low
--only-high-conffalseKeep only high-confidence findings
--difffalseShow only new findings vs. previous scan
--historyfalseList previously scanned URLs
--clear-historyfalseDelete stored scan history
--workers5Concurrent workers in batch mode
--no-flowsfalseSkip taint flow analysis
--silentfalseSuppress banner and progress output
--no-colorfalseDisable ANSI colors
--versionfalsePrint version and exit

Project Layout#

peelr/
โ”œโ”€โ”€ cmd/peelr/main.go
โ”œโ”€โ”€ internal/analyzer/analyzer.go
โ”œโ”€โ”€ internal/ast/ast.go
โ”œโ”€โ”€ internal/history/history.go
โ”œโ”€โ”€ internal/scorer/scorer.go
โ”œโ”€โ”€ internal/server/server.go
โ”œโ”€โ”€ web/templates/index.html
โ”œโ”€โ”€ web/static/app.css
โ””โ”€โ”€ web/static/app.js

Limits#

LimitValue
Maximum JS file size15 MB
Batch size in web/API mode50 URLs
CLI batch sizeUnlimited
Default worker count5
HTTP timeout20s per file
History storage~/.peelr/history/

Disclaimer#

Peelr is for authorized security testing and education. Only scan JavaScript from systems you own or have explicit written permission to assess.