Resources

People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!

The Security Researcher’s Guide to Mathematics- 1825

Bernhard Mueller    Reference →Posted 3 Months Ago
  • This article goes through the math required for being in Web3. This includes Linear Algebra, Abstract Algebra and number theory. Additionally, there are many points around real protocols that are using this math to explain why it's useful. Finally there are some other use cases, like Formal Verification that are thrown in there as well. This seems like a good reference for looking at things in the future.

CVE-2025-12443: Chrome WebXR Flaw Hits 4 Billion Devices- 1824

Aisle Research    Reference →Posted 3 Months Ago
  • Google Chrome is a browser that runs everywhere. Chromium is the open source browser engine underneath of Chrome that underlies Chrome, Edge, Brave and many more browsers. The post is about a memory safety issue that they found in the Chromium engine. The blog post really pushes towards autonomous security reviews because of the amount of new code that is being pushed. I understand the sentiment but not a huge fan of how it's pushed in the article.
  • WebXR is an API for virtual and augmented reality experiences in the browser. It's a great target to hit for memory safety issues because of the complexity. It's an evolving API that's under active development and is interfacing with complex 3D graphics plus new hardware components. Applications can manipulate positions, rotations and transformations using interfaces that represent data in a 3D space.
  • The vulnerable code path is around WebXR's matrix caching and JavaScript's ArrayBuffer semantics. A page can detach a typed array by transferring its underlying buffer to another context. This is a legitimate API and is used for zero-copy data transfers.
  • When handling the case of a cached array being detached, the Chromium engine had a bad fallback. It returns a freshly created zero-length array. So, what's the problem? During this code path, there's only a length check on the size in DEBUG builds. So, when ColMajorF accessing 16 array indexes, it reads 64 bytes past the end of the buffer that was just initialized. This creates an out of bounds read in the Chromium Engine.
  • To fix the vulnerability, the matrix is recalculated from the authoritative internal state instead of the cached array. This is in accordance to the WebXR specification. The Aisle tool additionally found two other locations where this was happening but the exploitability isn't mentioned in the article.

Securing Perplexity’s AI Browser from a One-Click UXSS - 1823

hacktron    Reference →Posted 3 Months Ago
  • The Comet browser has an extension built in that lets an AI agent perform any browser tasks a user can. Of course, driven by prompts.
  • Under the hood, Comet has an extension that runs in the background. It has a listener that is whitelisted for all *.perplexity.ai/* domains. With this extension, arbitrary actions can be asked to be performed. A single domain compromise or XSS would lead to a compromise then.
  • The company markets a hacking bot. After giving it some pages, it did find a DOM XSS (so they claim). Another human researcher found a simple JavaScript URI injection vulnerability that bypasses a Cloudflare WAF.
  • With access to the underlying API, they saw the command CALL_TOOL and RUN_IDLE_TEST. The former was a generalized tool executor while the latter took screenshots of the DOM of any page. Because this could handle file:// URIs, it could also read responses from arbitrary origins and local files.
  • They passed the usage to Hacktron to usage CALL_TOOL to see what it could do. One of them was GetContent to read the contents of a page. They tried to escalate to RCE from this tool's context but were unsuccessful.
  • The startAgentFromPerplexity command opened a websocket to the backend and forwarded the task information. The backend returns selectors based on the response and performs actions accordingly. Using this, they can get the browser to perform arbitrary actions. Good bug!

Pwning OpenAI Atlas Through Exposed Browser Internals - 1822

hacktron    Reference →Posted 3 Months Ago
  • An AI browser agent architecture works by granting a privileged origin control of the browser through an agent interface. In the case of Atlas, the focus of this post, they relied on the Mojo IPC interface. This interface is used for privileged pages, such as *.openai.com, to talk to the Chromium browser process to perform actions like opening browser tabs, navigating URLS, and more.
  • Having access to these Mojo APIs is super scary though. It's really not meant to be exposed to web pages because of its power on those domains. So, they decided to hunt for XSS vulnerabilities on OpenAI subdomains. After a while, they found one on forums.openai.com via postMessage. The post message handler received a URL and opened it from an arbitrary domain. So, you could send the JavaScript URI as a domain, and it would execute in the context of OpenAI. Yikes!
  • The post message listener was only activated on authenticated pages. Lucky for them, the website also had a login CSRF vulnerability. So, we have access to Mojo: now what?
  • The context of the page has a list of tools that can be used. kaur1br5 is the codename for the tool responsible for controlling the browser, including listing tabs, searching browser history and adding bookmarks. They tried adding javascript: bookmarks but this was rejected. They tried navigating to JavaScript URIs but these were rejected as well.
  • Eventually, they settled on list_tabs(). This allows for querying the full URL of the entire tab. This can leak information about browser-navigated URLs, including OAuth codes. The PoC leaks a user's GitHub OAuth token, which is pretty neat.
  • How was this fixed? It's not in the report. I would imagine they fixed the XSS and limited the impact of list_tabs to not include all information about a URL. Alas, this is still bad design and we probably haven't seen the end of this browser.

SVG Filters - Clickjacking 2.0- 1821

Lyra    Reference →Posted 3 Months Ago
  • Clickjacking is a classic attack in which an iframe is embedded within another website's content, transparently, to trick the user into interacting with that website. This article describes a variant of it they are dubbing SVG clickjacking. They drew inspiration for this from Apple's liquid glass design. Being a CSS, HTML, and SVG wizard, they also got it working in SVGs. They were surprised this worked on SVGs on top of an iframe; this was done via using feColorMatrix and feDisplacementMap. to change the color/location of pixels.
  • There are many SVG elements with the <fe*> typing. They take in one or more input images, apply operations to them, and output a new image. Some can load an image file. Others can move stuff around. Others can move pixels, blur, crop, expand, blend, and more. With this, it's a great list of utilities to make clickjacking more viable.
  • Their first example was inline a "secret code" from another website and turning it into a captcha via the feDisplacementMap flag to add blur. You ask the user to type in the code, and it looks somewhat realistic as a CAPTCHA. This isn't very useful because secret code pages like this shouldn't be iframable anyway.
  • The following strategy is around grey text hiding. Sometimes, there are textboxes with information that needs to be inputted. By using tricks with SVGs, the text box can be reskinned. For instance, instead of saying "set a new password," it can now say "enter your email". This is very confusing but still requires user interaction in order to do.
  • SVGs are Turing-complete if you get tricky with them based on the data. In practice, this means you can read pixels from the iframe to perform actions on it. Now, the SVG has this data and not the web page itself. This really means interactive, responsive clickjacking. They used this attack on Google Docs to link content with many steps. This would have been impossible before this technique.
  • They have a quote that I find interesting at the end: "I don’t think me discovering this technique was just luck though. I have a history of seeing things such as CSS as programming languages to exploit and be creative with. It wasn’t a stretch for me to see SVG filters as a programming language either. That, and my overlap between security research and creative projects - I often blur the lines between the two, which is what Antonymph was born out of."
  • They were experts in CSS and SVG prior to this. They had exploited client-side bugs in the past. With all of this knowledge in their head, this research was bound to be figured out by them at some point. I agree with their statement: it wasn't luck; it was a history of dedication that led them to this point. Great article!

The Chromium super (inline cache) type confusion- 1820

Man Yue Mo - GitHub    Reference →Posted 3 Months Ago
  • Inline cache is an optimization in the V8 browser engine that speeds up property access. When a function is invoked, Ignition compiles it into bytecode, collecting profiling and feedback each time it is invoked. Based upon this feedback, the JIT compiler can optimize this well at a later stage. An object type always has a map in the beginning of the object used for the type of the object and offsets to its other properties. Once the object data is known, this information no longer needs to be calculated, thus speeding it up.
  • The vulnerability resides in the handling of super properties of the inline cache. With the usage of both prototypes and classes, the hierarchical information about these types is complicated. For instance, parents' prototypes can even be different from those of their children.
  • The LoadSuperIC function is used to cache super property (parent) access. The property is NOT on the receiver this but on the parent prototype. Because of this, assumptions about the object types and maps should be examined in both the receiver object and the parent protocol type object to ensure correctness. Notably, the confusion between the receiver and home_object has led to vulnerabilities in the past, such as CVE-2021-30517. This bug led to type confusion due to differences between cached and real data access.
  • The final concept to understand the bug is around megamorphic inline cache. In the simplest case, each function has its own inline cache for each property access. Sometimes, different functions can share an inline cache, making it megamorphic; a system-wide stub for handling the lookup.
  • The function simple_api_call, used for interaction between the V8 engine and the Blink rendering engine, requires a particular byte format. When a handler is created for a property accessor, the wrong map type is used; it accidentally uses the lookup_start_object instead of the super type. Because there's a type check and the types can differ between parent and child, this creates a type confusion vulnerability.
  • Blink is responsible for the Web API that provides objects for rendering the web page, but those objects aren't normally accessible via JavaScript. When calling the Blink APIs, there is a very specific type check to ensure that the functions to Blink are the correct type and conform to the API call format. Because of the incorrect type usage check from above, it's possible to bypass the check for the type. In particular, a blink getter() can be called on an arbitrary type; this is their primitive. This type confusion is very powerful for developing further primitives.
  • The first new primitive is an arbitrary relative read of 8 bytes from the DeviceMotionEvent::interval function. By using this on the DOMMatrix type, the interval field, used to read data based on the interval data, we can specify the offset and read from there. The next primitive is getting an arbitrary objects address in order to corrupt it. The type Uint8ClampedArray in an ImageData type can be overlayed with DOMMatrix again to read the address of the code>Uint8ClampedArray array.
  • Finally, the goal is to create an arbitrary fake object. The getter of some objects sometimes returns JavaScript objects. By causing a type confusion on the value returned from the getter, an arbitrary write can be achieved. In particular, the signal property of Request returns a ScriptWrappable type. By overlaying the AudioData timestamp field with the request data, the timestamp is effectively the address of the object being returned. This is great for creating a OOB read/write primitive from an array. That's game over :)
  • Functionality in V8 is often implemented in multiple places, depending on the optimization level. This leads to the same bug occurring multiple times on tricky sections of code. They found the same bug in a different section of the JIT code, which is pretty interesting. So, if a codebase has made a mistake once before, check other places where this issue could also appear.
  • The vulnerability was complicated but a variant of several bugs. The exploitation requires very deep knowledge of the API interactions with Blink, but gave a very powerful primitive once it was understood. The more complex the target, the better primitives you likely have. In this case, it was worthwhile to take this type confusion to RCE in the sandbox by understanding this integration point. Great post!

Getting from tested to battle-tested- 1819

Doug Patti - Jane Street    Reference →Posted 3 Months Ago
  • Jane Street is a quantitative trading firm that takes code quality seriously. One of the significant ways to improve code quality is through tests, as they act as documentation, a reminder of mistakes, and boost confidence during a refactor. Because of this, they wrote a framework called Aria to test their complex systems.
  • They have a list of tests types that they use internally:
    • Unit tests. Modules and data structures without any side effects.
    • Integration Tests. Simulated networking layer that allows for fine-grained interactions between services.
    • Quickcheck. Random orderings of events that can feed a simulation.
    • Version Skew. New client library changes work with existing servers and vice versa.
    • Fuzz tests. Random data and see what happens.
    • Lab tests. Performance regressions that run nightly are similar to production.
    • Choas Testing. Change the environment with things like service restarts to see how the service reacts to it.
  • All of these have value, but the integration testing is the most crucial bit. Expressive tests, fsat, and deterministic allow for better coverage. The Antitheseis tool runs in a virtual machine with a completely deterministic hypervisor. This allows for faults to be created at weird points, that can potentially find bugs as a result.
  • The configuration of this tool allows for simulated production in test to find crazy edge cases. This is a double-edged sword though: a larger input space takes more time to run. So, the tool includes a powerful exploration engine for finding edge cases.
  • They have an example vulnerability that they found via this testing framework. It only happened after a specific server was restarted, before a ring buffer was filled and if the client sends a request for data prior to a snapshot. Because of this case, the client read corrupted data. But why? When the client was written, the server didn't have a snapshot feature so this issue wasn't even possible. Antithesis also gave them debugging tools and reproduction steps to make it possible to reproduce.
  • A good post on the benefits of testing. A bit too focused on the specific testing framework they used by the end, but the product demo was cool nonetheless.

Higher Bug Bounties Won’t Stop Hacks- 1818

samczsun    Reference →Posted 3 Months Ago
  • Web3 has three key steps that almost every serious project does: write good tests, get audits/contests on the codebase, and start a bug bounty program. This has substantially reduced the number of vulnerabilities in recent years.
  • Every once in a while, one of these projects with a significant bug bounty program gets hacked. Yearn and BalancerV2 are great examples of this. They are battle-tested and have large bounties. How can we prevent this from happening? Some folks suggest that higher bounties would have protected the protocols. The blog post dives into why this isn't the case.
  • At times, a bad actor will return the funds but keep a small portion, like 10%. There's a difference between the total value locked (TVL) and the treasury. TVL is usually user funds, and treasury is protocol funds. The protocol has legal authority to spend funds from the treasury but not the TVL. Unfortunately, the risk scales with TVL, but the security budget doesn't; the amount of funds at risk doesn't directly correlate with how much a protocol can pay out because they don't own the money themselves.
  • The second issue is around capital efficiency. How do we allocate funds for a bug bounty program? Raising the bounty makes it inefficient because this money will just sit around. Protocols would need to keep this on hand in case of a critical vulnerability, instead of using the money on other things, like more audits.
  • Raising the bounty creates a perverted relationship between the whitehat and the protocol. If there's a horrible vulnerability at launch that is unlikely to be duplicated, then the whitehat is incentivized to hold onto the bug until there's a lot of TVL at risk to maximize their bounty. Whitehats that do this full-time are unlikely to look at very battle-tested code because the rate of return is very low. There's really no dollar amount that would make this effort worthwhile.
  • So, what can we do? Reaudits. Get the code looked at again and again. In other industries, audits are conducted annually to ensure compliance. So, why not do that here as well? Having a bug bounty program is part of the process. But, raising it from $5M to 10% of funds at risk wouldn't have the positive effect that people think it would. Overall, a great article on the state of security in crypto.

We found cryptography bugs in the elliptic library using Wycheproof- 1817

Markus Schiffermuller    Reference →Posted 3 Months Ago
  • During the authors internship at Trail of Bits, they setup the tool wycheproof on a JavaScript library called elliptic. The idea behind this package is great: let's take a collection of known attacks against cryptographic protocols and run them against the library. This plugin drastically improves the security confidence in a library imo. They claim this test suite would be good for CI/CD.
  • To do this, they had to setup a harness around elliptic for wycheproof. Once this was done, they ran the tool over the library. They had several findings that they started to triage as either false positives or real findings. When trying to integrate, there's also a question of did I set this up correctly or are these issues my fault?
  • The first issue they call out is around EdDSA signature malleability. Ellipic curves have two valid y points. In reality, only one of these should be allowed, according to specifications. This is technically valid math but bad for many cryptography purposes. This could lead to consensus failures or replay protection bypasses. Personally, I don't think that cryptographic libraries should enforce the malleability because it is desirable in some cases but I'm not a cryptography expert so what do I know. This was the vulnerability that was fixed while the next one was not.
  • The second bug is that hashes with leading zeros can cause a signature to become invalid. This appears to be a string parsing bug where the conversion new BN(msg, 16) removes the leading zeros. When it's used later, some offset math is wrong as a result. This bug was never fixed.
  • The usage of the cryptography testing library is interesting. However, I'm not sure that these are security "vulnerabilities". I agree that they differ from the specification. In the context of blockchain where two libraries need to have perfect parity, these are both bugs for sure. In the context of causing damage via signature validation, the first one has merit in specific situations while the second does not.
  • Funny point at the end: Wycheproof test developer Daniel Bleichenbacher independently discovered and disclosed issue #321, which is related to this discovery. This is a really famous cryptography person who discovered some attacks on RSA back in the day. It's cool he's still in the game!

yETH Exploit Deep Dive- 1816

kaden.eth    Reference →Posted 3 Months Ago
  • Yearn got hacked for a third time in its long history. The author of this post dove into how the exploit works and explains it. It's important to understand what's going on and not just bookmark it. The yETH uses a hybrid AAM type. It acts as constant sum when the tokens are balanced, to keep prices stable and constant product as they get further out. The article shows a good graph of this.
  • The function _calc_supply() is used for generating the values of the curve. Notably, it's figuring out what the supply is from the constant-product and constant sum values. This is done with an iterative approximation to converge to a new supply. The constant product term r is recomputed each iterate as the current value multiples by the new supply and divided by the previous supply. The goal is for the smoothness of the curve to get better over as more tokens are put into the pool.
  • So, what's the vulnerability? If the decrease in the supply of an iteration is large enough, the the constant product term can round down to zero. Once this happens, it's 0 for the rest of the loop and poisons all value that it touches. Effectively, this creates a zero constant product term with a constant sum curve ALL the time. This is fine in the middle but is real bad on the edges because we are supposed to use the constant-product formula.
  • The attack works as follows:
    1. Perform swap that will trigger the zero constant product term.
    2. Use this to receive more LP tokens from the pool than intended with the unbalanced reserves.
    3. Fix the constant product term back to the original during liquidity removal.
    4. Withdraw tokens. These will now be more than what you started with.
    5. Do it again and again...
  • There's actually a second bug in this code that allowed them to steal even more funds. When calculating the value sp, there are several unsafe math functions being used; this means that integer overflow protections are not enabled. In the math (l - s * r) / d it's possible to make s*r larger than l to cause an integer overflow. This mints a crazy amount of LP tokens, which they use to steal even more money. It should be noted that this is only possible to do because of the first vulnerability above.
  • The code appears to be a completely isolated product. Yearn v2 and v3 share zero code with yETH. This was an older product with millions still sitting in it. It's interesting how this occurred. Great articles describing the bug and the situation surrounding it!