Jason Haddix’s application-analysis talk is deliberately not a “how to do XSS” tutorial. It answers the harder question of where bugs live in a large app and how he systematically maps a single target so his manual testing lands on the right endpoints and parameters.

Mental hurdles that stop hunters before they start

Haddix opens with the psychology of attacking a big target, because he still hits these blocks himself. He names five self-defeating fallacies. Client reputation is the belief that a hardened brand like tesla.com, staffed by top-tier security engineers, is unbeatable. Pre-testing is the trap of reading a program’s leaderboard (he uses GitHub’s, showing prior SQLi, XSS, IDOR, and privacy finds) and concluding everything worth finding is already found. Size is analysis paralysis: opening something like Salesforce in Burp, seeing thousands of parameters and modules, and freezing. Maturity of purchasable or open-source software is assuming years of community and researcher scrutiny have exhausted a COTS, SaaS, self-hosted, or OSS codebase. The fifth and most common is only touching the surface: hunters overcome the first four, land on the domain, and then never create accounts, testing only the public unauthenticated shell. The real attack surface, he stresses, is inside authentication: profile sections, integrations, paid-account features, upload/export functions, admin tools, user levels for IDOR, customer data, and persistent user input. His blunt takeaway is that the first four hurdles do not matter, because every single application has bugs regardless of who has looked at it, so you recognise the hurdle and hit the target hard anyway.

Layered target model and technology fingerprinting

Haddix pictures a target as a stack of layers that each need separate testing: open ports and services at the base, then web hosting software, then the application framework, then custom code, and finally application libraries and integrations. The layer people most often skip is the server itself, and in bug bounty the first layer is usually in scope because it is bound to the assigned domain. He repeatedly finds admin panels, installed software, and remote-administration services on high (or low) ports that others never scanned. For fingerprinting the stack he runs the browser extensions Wappalyzer and Whatruns to read off server software, tag managers, analytics, and JavaScript frameworks, and records everything in a mind map for later reference. For an automatable, command-line equivalent he uses webanalyze, giving both a manual in-browser path and a scriptable path so the step can be glued into an automation framework.

For known-vulnerability and misconfiguration checks against non-custom code (CVEs, framework logins, default creds), his primary tool is Nuclei, which he notes carries over a thousand CVE templates, 100-plus informational detections, ~500 admin-panel checks, and ~150 miscellaneous checks. Alternatives he rates are Jaeles (by Jesse JJ) with a comprehensive CVE library, retire.js for outdated libs and frameworks, plus Sn1per, Intrigue, and go-fingerprint; combined, he argues the open-source CVE tooling now rivals or outpaces enterprise scanners like Nessus. He addresses the criticism (from his friend Corbin) that running Nuclei is a competitive disadvantage: true if you run stock templates at the same scope as everyone else, but very effective against a green-field domain or subdomain your recon surfaced that nobody else has. His force multiplier is writing custom Nuclei templates, which he calls the easiest template authoring of any tool. He runs a TweetDeck feed polling every five seconds for vulnerability-class keywords (local file include, path traversal, broken authentication, and so on), treats it as a threat-hunting feed, and whenever a fresh CVE, one-day, or thirty-day bug is not yet in the Nuclei library he ports it into his own check. That habit has built roughly 120 templates outside the stock library, which have paid out across heavily-tested scope precisely because they are not what everyone else runs.

Content discovery as the highest-yield activity

Haddix states plainly that effective content discovery leads to more bounties than anything else he has seen, because finding every endpoint and parameter is what wins. The fuzzing tools (wfuzz, ffuf, gobuster, Turbo Intruder, dirsearch, dirb, and roughly twenty others) are only as good as the wordlists fed to them; his current favourite tool is Feroxbuster, largely for its recursion. He selects wordlists by technology, drawing heavily on the assetnote wordlists at wordlists.assetnote.io (built mostly from BigQuery and the HTTP Archive). For IIS, Microsoft frameworks, or Azure he uses the HTTP Archive and shortname lists; for PHP or CGI, the httparchive CGI and _php lists; for a generic API, the api-routes and swagger lists plus Daniel Miessler’s SecLists api-endpoints; for Java apps, .jsp, .jspa, and .do/action extensions; and once technology-specific brute forcing is done he falls back to a generic content list.

Framework config files get special attention, because endpoints exposing database connection strings should never be public yet sometimes are (through a bad access rule or a site that was never meant to be live), and can lead to large bounties. His example is appsettings.json / ASP.NET site config surfaced in someone else’s bounty. He advises researching where each new framework stores its DB references and config files, writing those paths down, and continually growing a personal wordlist rather than relying only on generic ones. Where source is obtainable he builds wordlists from it: Daniel Miessler’s source2url parses an install directory’s routes and endpoints into a list; source, COTS installs, and even source code can often be pulled from Docker Hub images people have dumped online. For SaaS or paid software he suggests requesting a demo, or buying and self-hosting the app, to harvest a detailed path list. Scavenger (a Burp plugin by 0xDexter0us) generates a custom wordlist from words present on the site, surfacing target-specific terms (his example: Twitch producing “streaming” or “streamer”). For historical discovery he uses gau (pulling endpoints and URLs from AlienVault OTX and the Wayback Machine) and the newer waymore, which additionally downloads the archived pages themselves and parses them for parameters, endpoints, and links, giving “way more” coverage. He calls out recursion as one of his biggest earners: brute forcing past a path that returns 401 (for example continuing beyond an /admin/dashboard that 401s) frequently surfaces an authorization bypass deeper in the chain that non-recursive scans miss. He also parses mobile apps with apkleaks, extracting endpoints from a compiled APK grabbed from a public store, since the mobile API is usually served from the same in-scope domain. For long-term targets he flags change detection: subscribing to the target’s newsletter, joining its affiliate program for early feature access, watching its conference talks, and monitoring with changedetection.io.

Six questions that frame application analysis

Before hunting, Haddix interrogates the app with six questions that shape which bug classes to prioritise. First, how does the app pass data (REST, resource/parameter/value, a web service, or an SPA firing API calls), because you cannot test anything without understanding data flow. Second, how and where does the app refer to users (in cookies, in API calls, as a UID, email, username, or UUID/GUID), which underpins IDOR and other authorization attacks. Third, does the site have multi-tenancy or user levels (admin, regular, tenant/invited viewers, and unauthenticated functionality), the basis for privilege-escalation IDORs; he uses the Autorize extension for IDOR testing. Fourth, does the site have a unique threat model, a contextual look at data beyond the usual credit-card and PII, such as Twitch’s primary stream key, so you also ask creative ways to reach that custom-sensitive asset. Fifth, has there been past security research, which he finds by googling ” vulnerabilities”, reading write-ups (Detectify’s DOM XSS on Tesla, Sam Curry’s blind-XSS-in-the-car story), and reviewing HackerOne and Bugcrowd disclosure histories, both to regression-test old bugs against new patches and to profile the target’s weak spots. Sixth, how does the app’s framework handle each vulnerability class, read straight from framework docs (for example Laravel’s XSS, CSRF, and injection protections); if a framework has a strong built-in defence he deprioritises that class and hunts others more likely to be inherent.

Spidering, JavaScript, and parameter analysis

Once framed, he spiders to enumerate links and parameters. In the GUI he uses ZAP (Attack, Spider) or Burp (Scan, Crawl) with crawl strategy set to fastest and “never stop crawl due to application errors”; on the command line he uses hakrawler and gospider, which also parse robots.txt and pull from JavaScript, so they can bake into automation. JavaScript parsing is treated as its own content-discovery front: pull all JS, especially custom (non-framework) files, and extract endpoints and parameters into the sitemap. LinkFinder was the long-standing tool but never parsed inline JavaScript, so he now uses xnl-h4ck3r’s tooling with improved regex that parses both JS files and inline script, plus the same author’s Burp extension GAP for GUI users. For minified or obfuscated JavaScript he admits manual reversing is hard; beautifier.io helps somewhat, and he points to research by (m4ll0k/matsu-style) tooling that dynamically reconstructs obfuscated JS into readable form, still early and unreleased. For JS libraries and dependencies he again relies on retire.js for its large vulnerable-version database.

Parameter analysis is what he calls his hunting superpower, first released in his DEF CON tool HUNT. The idea is statistical: he took every vulnerability across the bug-bounty platform he worked for, mapped each to the parameter or route it lived in, and ranked which parameter names most often carry which bug class. For IDOR, for example, the high-signal parameters are id, user, account, number, order, key, and email. Others extended this by mining URLs and vulnerabilities from sources like the XSS archive and HackerOne disclosures, porting the lists into gf (with gf-patterns) to grep large URL sets for suspicious parameters. He notes many public repos clone his original lists but some add good new ones, and he plans to merge them into a project called sus-params. In Burp, HUNT (his now-unmaintained Bugcrowd tool) did this, and the still-maintained paid option is Burp Bounty (~$75), which both adds active-scan checks and alerts on known-vulnerable parameter names.

Heat mapping: where the bugs cluster

Heat mapping is Haddix’s attempt to codify hacker intuition into the specific places he looks first, kept as a mind map on his desktop; combined with parameter analysis it focuses his effort. He targets six areas. Upload functions come first, prone to injection, XSS, XXE, sometimes SSRF, occasionally shelling the server depending on the parser, and they also reveal where the app stores data. Content types are filtered in Burp by what the app returns: multipart forms he circles in red because he has “never met a multipart form that was secure,” content-type: xml flags XXE candidates, and content-type: json flags metadata endpoints and web services to attack. APIs he probes for JSON returns, hidden methods (brute forcing HTTP methods), and missing authorization on admin or higher-privilege methods reachable by low-privilege users. The account section holds most stored data, so he checks profiles and custom application fields for stored XSS and server-side template injection (where a template engine is in use), and integrations with third parties as a way to smuggle payloads into the app. URLs are checked nearly as much as uploads: any parameter referencing a path or URL is filtered in Burp and tested for SSRF, open redirect, and sometimes authorization bugs. Application errors come last: he runs Logger++ in the background while spidering and fuzzing, then inspects any exotic (non-default) error to see what triggered it, since those often mean he was close to an injection or could crash the app for an application-level DoS. He keeps all of this knowledge (fuzz strings, vulnerable parameters, per-class notes, recon seed discovery, tool syntax) in Notion so each new project starts with everything learned on the last.

Key takeaways

  • Every application has bugs; the four “it’s too hard / already tested” hurdles are fallacies, and the fifth (only testing the unauthenticated surface) is the real trap since bugs live behind login.
  • Test all layers: ports and services, hosting software, framework, custom code, and libraries; the server layer is most often skipped and most often rewarding.
  • Fingerprint with Wappalyzer/Whatruns (or webanalyze), then run Nuclei/Jaeles for CVEs, but win with custom Nuclei templates fed from a daily TweetDeck vuln-keyword feed.
  • Content discovery drives the most bounties; pick assetnote/SecLists wordlists by tech stack, grow a personal config-file wordlist, mine source via source2url and Docker Hub, and lean on recursion (brute forcing past 401s finds auth bypasses).
  • Use gau/waymore for historical URLs and apkleaks for mobile endpoints on the same in-scope domain.
  • Frame every app with six questions (data flow, user references, multi-tenancy, unique threat model, past research, framework defences) to decide which bug classes to prioritise.
  • Parse JavaScript (xnl-h4ck3r tools / GAP, retire.js) as content discovery, and use statistical parameter analysis (HUNT lists, gf-patterns, Burp Bounty) to target the parameters most correlated with each bug class.
  • Heat map to six clusters: uploads, content types (multipart, XML, JSON), APIs, account/stored-data, URL-referencing parameters (SSRF/redirect), and exotic application errors; keep it all in Notion.

Sources