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!

Github Secrets exposed due to RCE in Formatter Action from pull_request_target event - 1719

Anthony Weems    Reference →Posted 4 Days Ago
  • GitHub Actions permissions are really complicated to think about when secrets come into the mix. If someone makes a PR, do they have access to the secrets? There are different modes of these but it really makes a difference what code is ran on the repository.
  • In the case of a Java formatter in the typically "safe" pull_request_target, it was checking out the user's PR from the Pull Request. By placing in a malicious pom.xml file, RCE could be gained in the context of the PR. Since the action can have secrets, this is a serious security issue. Using the secrets and ACCESS_TOKEN, it may have been possible to edit the repository itself.
  • This attack is known as a "Pwn Request". To protect against it, developers should be very wary about externally facing actions on GitHub. Additionally, scope tokens down as much as possible. Good write up!

v1 Instance Metadata Service protections bypass - 1718

Anthony Weems    Reference →Posted 4 Days Ago
  • Instance providers, like GCP and AWS, have a service for getting credentials local to the server. Obviously, getting an SSRF to get this information is horrible for the client. So, some protections have been added to make this harder. One of these is the requirement of the Metadata-Flavor: Google header.
  • While on a pentest, the author of this post noticed that adding an extra slash to the instance removed the requirement of this header! But why!? Using http://169.254.169.254/computeMetadata<</>>/v1/instance/ with a single extra slash did the trick. Sometimes, fuzzing and trying weird things is the way to go! Our systems are just so complex nowadays that it's hard to understand how they work.

Cross-Site Request Forgery- 1717

Filippo Valsorda    Reference →Posted 4 Days Ago
  • Whether Cross-Site Request Forgery (CSRF) works or not is a combination of intentional security features and accidental legacy protections. CSRF is often known as the "session riding attack". When a website makes a request when you visit the page, cookies are always sent. So, what happens when malicious.com requests amazon.com? This post discusses when and why CSRF exploits work in excellent detail.
  • Cookies have been and will continue to be used on requests. So, the goal is to prevent attackers from using them via a CSRF attack. A classic mitigation is double submit protection; this places a large random value in the request body and in a cookie. Since the attacker can't read cookies cross-site, this works well. "Cookie tossing" can be done to remove this cookie if the attacker is on the same site though. So, the usage of __Host- can be used here instead.
  • The SameSite cookie flag can be used to prevent CSRF at a browser level. This has three modes: none, lax and strict. Some browsers default to none because it would break many SSO flows otherwise but others default to lax, breaking many CSRF attacks. Some browsers even default to just two minutes after the cookies were set. This is a very good protection but does have some integration issues.
  • The Origin header is a surprising safeguard as well. Since this cannot be spoofed, if the backend application knows its domain, it can reject based on the Origin very effectively. This creates some edge cases around the header being removed by Referrer-Policy and by Chrome extensions though.
  • CORS is not meant to protect against CSRF, but it sort of does! When a "non-simple request" is made, a pre-flight options request is made. Since this is coming from the wrong origin, the browser will reject the request. This is very limiting for CSRF attacks but there are clever work arounds.
  • Browsers recently introduced Fetch Metadata. On a request, the Set-Fetch-Site header will set it to cross-site, same-site, same-origin or none. Since the browser sets this, it provides excellent CSRF protection by checking this header on the backend. According to some articles, it is now the recommended way to prevent CSRF attacks.
  • Overall, a fantastic article on the state of CSRF protections in 2025. I'll be referencing this article for years to come!

Live EigenLayer Bug Discovered During Sidecar Security Review- 1716

Andy Li    Reference →Posted 4 Days Ago
  • EigenLayer introduces restaking on Ethereum. This allows staked assets to secure other applications, known as Actively Validated Services (AVS) rather than just Ethereum. EigenLayer runs alongside Ethereum, so its implementation is highly security-sensitive.
  • The EigenLayer sidecar is an off-chain worker supporting the main logic in the smart contracts. It listens for on-chain events, processes the data and performs computations on it, such as Rewards. AVSs submit reward details on the chain to the RewardsCoordinator.sol contract, where the sidecar process processes the amount and duration information.
  • The Solidity contract attempts to do input validation on the duration: it must be a divisor of CALCULATION_INTERVAL_SECONDS. This is checked by doing duration % CALCULATION_INTERVAL_SECONDS == 0. Technically, zero satisfies this requirement.
  • Within the off-chain codebase, there is a SQL query that performs division. This leads to a divide-by-zero error in the database. They found this issue by first seeing the division within the SQL query (sink) and tracing it all the way back to the source. I typically don't trace divide by zero bugs this way so that was interesting to see.
  • The impact is slightly dubious to me. A crash or exit doesn't necessarily mean a Denial of Service in all cases. Error handling and continuation need to be taken into consideration. In this case, since the SQL query failed, all AVS operators' sidecar operations for reward calculations would be halted. A good bug and an interesting trace!

Compiler Bug Causes Compiler Bug: How a 12-Year-Old G++ Bug Took Down Solidity- 1715

Kiprey - OtterSec    Reference →Posted 4 Days Ago
  • The post starts with a small amount of Solidity that crashes the compiler:
    // SPDX-License-Identifier: UNLICENSED
    pragma solidity ^0.8.25;
    
    contract A {
        function a() public pure returns (uint256) {
            return 1 ** 2;
        }
    }
    
  • Eventually, they traced it down to a line of C++ code on the G++ compiler backend that leads to infinite recursion. This turns out to be a 12 year old bug in G++, an outdated comparison operation in Boost and a small rewrite in C++20 that led to this crash.
  • In C++, there is functionality called overloading where the compiler can choose implementations for operations like equality. A member function has priority over a non-member function to overwrite this. G++ doesn't always follow this rule though. Clang would choose the member function and the G++ issue was reported 12 years ago.
  • In C++20, the spaceship operator (<=>) was introduced. This allows for comparisons to be done via overloading as before but will also do the reverse check as well. a=b and code>b=a. This rewrite becomes recursive to do the comparison over and over again if you're not careful.
  • The Boost rational class implemented both a member and a non-member function for operator==. Under C++17, this was safe because of the member vs. non member bug was fixed. However, with C++20 and G++ < 14, G++ would incorrectly choose the non-member operation first. This leads to an infinite recursion bug!
  • The Solidity codebase uses boost::rational to represent some compile-time constant expressions. Because of this, Solidity inherited the bug mentioned above. To have this happen you had to be using G++ < 14, Boost < 1.75 and C++ enabled for Solidity builds. This crash occurs with any compile-time rational comparisons.
  • Although it's not a security vulnerability, it does show how fragile modern stacks can be. A bug from 2012 led to a broken compiler. Neat!

Gato X - GitHub Actions Security Scanner- 1714

Adnane Khan    Reference →Posted 4 Days Ago
  • Security scanner for GitHub Actions. Looks for Pwn Requests, TOCTOU issues, command injection and several other issues. It even has some post compromise exploitation it tries to do.

Fooling the Sandbox: A Chrome-atic Escape - 1713

Vincent Yeo - STAR Labs    Reference →Posted 8 Days Ago
  • The author of this post was exploiting a Windows vulnerability to escape the Chrome renderer Sandbox to become SYSTEM. The original vulnerability is a time of check, time of use (TOCTOU) issue on a user-provided pointer. By changing the userland pointer to be a kernel address, we obtain a partially controlled write.
  • In just Windows, this was a straightforward exploit. Once you use the bug to overwrite the Control bitfield in SepMediumDaclSd, it will skip the integrity check. Next, get the token of the renderer process via NtQueryInformationSystem. These steps are the same for the Chrome sandbox escape, but there are a few additional steps to take.
  • From the Chrome sandbox, this wasn't the case, though. The integrity level is untrusted, the job disallows the creation of child processes, and there was no privileges on the token. So, using this vulnerability requires some more work to exploit in this case.
  • When trying to call NtQuerySystemInformation to get a token, they got an access denied error because the renderprocess runs at a low privilege level. To fix this issue, they used the previous OOB write to overwrite the SE_SACL_PRESENT field to skip the integrity control check. Since this was a 32-byte write, they had to be clever at the byte offset to do this at though.
  • The second issue was another access issue around job integrity. The renderer process cannot call CreateProcess. The solution? Inject the code from the renderer process into another process (winlogon.exe) and have it call CreateProcess instead. This gives them code execution as a privileged user from Chrome!

Finding Mispriced Opcodes with Fuzzing - 1712

Max Ammann - Trail of Bits     Reference →Posted 8 Days Ago
  • The author of this post was working on a project for the custom blockchain runtime Fuel VM. They created a fuzzing setup with special invariants to try to catch some bugs. The Fuel network team initially used libFuzzer and cargo-fuzz, but this was slow and didn't make any internal calls.
  • To get better coverage, they used a shim to inject in LibAFL. This allowed for the execution of 1K per second on an eight-core machine versus the original 50 per second.
  • An additional redesign was around the input generation. Originally, the input was a simple byte vector with not much else. Since the Sway language compiler has data interleaved with the actual instructions, the byte vector was ineffective. The input is now a byte vector that has the script assembly, script data, and a magic value separating them. Using this, they used the Sway compiler to obtain a large number of test inputs.
  • They ran into some issues with fuzzing. The program secp256k1 0.27.0 version is not compatible with cargo-fuzz because it fails all the time. So, they had to use a different version for fuzzing. Secondly, they ended up modifying the FuelVM somewhat to add the offset into the execution data to have this within the context of the program.
  • It is assumed this fuzzer was used for a large number of reasons, but a major one they used was gas usage. In most blockchain runtimes, different opcodes cost different amounts of the native currency to run. So, they wanted to see if the gas usage correlates with the execution time. They ran the fuzzer and plotted the information. Within the document, there are several for weird outliers.
  • Through doing this and finding the outliers, they were able to find opcodes that should cost more in gas. In the "lessons learned" section, they state that fuzzers should be run until new coverage stops, pause the campaign when issues are found to let developers fix them, and save the corpus generated from each test. This is because it represents hours of refinement to find the edge cases in the codebase.
  • Overall, a great look into setting up a legitimate fuzzing campaign. It was a unique reason to use fuzzing that turned up good results for them.

How we Rooted Copilot - 1711

Vaisha Bernard - Eye Security    Reference →Posted 8 Days Ago
  • Copilot added a Python sandbox running Jupyter Notebook that can execute code. Within CoPilot, we can use %command to execute arbitrary commands in the environment. The author points out that it works sometimes and is like a child. After some time, though, it becomes more and more consistent in execution. I am guessing that it sees its past actions and is more likely to perform the actions as a result.
  • They read files from the system using this technique. When trying to read binaries, there are many mistakes. So, they had to base64 encode the binaries. After getting all of the files, they can steal the server code for this application that they are interacting with.
  • In the bash script that starts the server, it executes a set of commands every two seconds. Most of these are executed with lower permissions, but not all. When performing this loop, it calls pgrep with non-dropped privileges AND with an absolute path. By changing the PATH variables, it's possible to change the binary being used and execute it as root.
  • Funnily enough, there's zero impact to escalating this to root. Still some good alpha on using CoPilot and a good privilege escalation.

A Novel Technique for SQL Injection in PDO’s Prepared Statements- 1710

Adam Kues - Searchlight    Reference →Posted 8 Days Ago
  • PHP contains a library for prepared statements with PDO and contains prepared statements. In most languages, this is sufficient for preventing SQL injection. However, PDO in PHP isn't a true prepared statement. PDO attempts to do the escaping itself instead of binding the information, like many other languages do, which requires their own custom SQL parser.
  • There's a great quote that sums up the whole challenge: "if we can trick the PDO parser into parsing our input as a bound parameter where it shouldn’t, we can get an SQLi in a situation that would otherwise be impossible." They created this as a CTF challenge that contains a potential injection point within a column name; this is because column names cannot be bound. So, the parameter should be escaped adequately with backticks, but this isn't enough!
  • The parser contains a nice specification for how it parses the data. The type ANYNOEOF is defined as [\001-\377]. When adding a null byte and a question mark - ?\0 - it will see this as a SPECIAL and note a literal now. Naturally, this error occurs because it's trying to bind two things in the query. However, adding a comment - code>?#\0 - can easily remediate this problem. So, are we done? Nope! Still some more trickery for this to work.
  • Now, the first parameterized item in the query is used with OUR question mark and has to have a value. The substitution turns this into 'x'#\0, where the x is a controllable parameter and the parameterization adds the single quotes around the query because it thinks it's a string. There's another issue now: a null byte cannot be in a comment. The problem can be solved by adding a semicolon between the comment and nullbyte to make it a new line. With the stolen parameter x`;# and the same column name, this problem is solved.
  • The column 'x does not exist, though. What now? PDO still thinks that our injection point is in a string! Placing a \ as the first character in the string causes some MAJOR havoc. It will escape the single quote to allow for a context escape. The column name \?#\0 and the stolen parameter with x` FROM... allows us to create a legitimate query to perform SQL injection. Neat!
  • Older versions of PHP are much more susceptible to these types of attacks. This is because the lack of usage of backticks allowed for any injection of a question mark or semicolon, leading to SQL injection. There are numerous other ways to exploit this by creating a desync between the parameterization data. Overall, a pretty slick blog post on a fun SQL injection technique.

More Resources:

123456....168