CTF Challenges

A collection of small AppSec, cloud and ML security problems.

Back in 2022, I wrote a handful of challenges that I hosted on my old site. They were hosted on AWS and despite them being a random vacation project I talked to people who told me they actually tried doing them, which was pretty surprising! I had to take them down when I migrated some stuff off AWS but I rebuilt them on Cloudflare Workers. These six small challenges are aimed at people learning AppSec — more about understanding how things work than exploiting some known vulns.
Flags look likeflag{some_words_here}; you can check them below as you go. Everything runs on a Cloudflare Worker.

  1. Regex

    start hereinput validation

    An API that will not talk to you until you can read its validation patterns.

    Open challenge

    Hints & notes

    Hint 1Read all of the patterns properly before you start guessing at values.

    Hint 2One of them is worth a second look.

    Why this oneWith modern applications you really should be identifying cases where an application is not using some sort of regular expression to validate input. In cases where a service just accepts anything from a user it opens the door to a lot of problems. On the other hand if you have an app that forces all input to be alphanumeric strings it really limits what an attacker can do.

  2. Data Formats

    encoding

    A puzzle for figuring out valid nested inputs with limited information.

    Open challenge

    Hints & notes

    HintSend it an empty object to start and just keep fixing whatever it complains about.

    Why this oneWhen testing modern applications there are going to be situations where you are passing in different types of data formats - which require you to take steps to properly massage your inputs. Its not unusual for a client to provide you with some very opaque instructions for how to make a request and you need to figure out how to get it to work. Since applications are written by real people with real problems there is no shortage of extremely weird types of input you will need to be able to perform.

  3. Another challenge about making a set of valid inputs given the context provided.

    Open challenge

    Endpoints
    Hints & notes

    HintThere are 720 combinations.

    Why this oneThis is the one challenge here where you are expected to make a pile of requests, and picking the one interesting response out of a few hundred boring ones is honestly half the exercise.

  4. Codec

    scripting

    A token wrapped around a value wrapped in three encodings.

    Open challenge

    Endpoints
    Hints & notes

    Hint 1You get handed the signing key and the algorithm. There is nothing clever to do there.

    Hint 2It is an encoding chain. Work out each layer in order, then go back the other way.

    Why this oneTo be clear this is not a JWT attack challenge - you get handed the signing key and the algorithm, so there is nothing clever to do there. It is an encoding exercise that happens to be wearing a token as a coat.

  5. MCP Tool Audit

    newai / agents

    An MCP server exposes a code-scanning tool to a model. The tool definition puts no constraints on its input. Find what that costs.

    Open challenge

    Hints & notes

    Hint 1You are reviewing it. Have a look at what the tool says it accepts, and then at what the server does with that afterwards.

    Hint 2Trying to do this kind of review through the model at runtime is pretty difficult - you really want to be reading the source or hitting the server directly, so both of those are available to you here.

    Why this oneI wrote at the end of last year that tools need to be defined with restrictive inputs, because you cannot control what a model is going to generate and you have to treat all of it as extremely tainted. This is basically that, as a puzzle.

  6. Model Forensics

    newml supply chain

    A model checkpoint downloaded from somewhere less than reputable. Work out what it does when you load it — without loading it.

    Open challenge

    Hints & notes

    Hint 1Figure out what happens to you when that file gets deserialized. Try to do that without just loading it and finding out, because that is sort of the entire point of the exercise.

    Hint 2The one in this challenge is harmless, but you don't know that when you start, and “I ran it and nothing bad happened” is not a review.

    Why this oneIf you do any work around ML systems this is a genuinely useful thing to be able to do. Being the person who can look at an artifact and say what it does before anyone runs it is worth a lot in a room full of people who are keen to get the model loaded.

What these are, and who they are for

This page is a collection of different challenges broken down into different categories. A lot of these are pretty simple, but hopefully at least a little bit interesting! My primary goals in putting these together were:

Be non-destructive - I wanted stuff that I could just leave up without needing to dynamically spin up and down infrastructure. As such I want to avoid situations where people get shells and can break the flow for others. This also helps with keeping the costs low enough to just keep running.

Be instructive - There is an amazing amount of really, really good technical content out there if your primary goal is to learn how to exploit specific vulnerabilities. My main thing in teaching people about how to do good assessments is that they need to worry less about specific vulnerabilities and more about how the application they are testing works and how they can break that. A lot of these are more geared towards needing to understand how to do something, more than out to break something.

Be accessible - I work with a lot of really junior people in security - a lot of people who are extremely smart and eager to learn but are often intimidated by the scope of work that is out there. In almost all cases once people get a bit of confidence in them that they can actually do things they tend to blossom into amazing information security professionals. A lot of times doing public CTFs can be a tad demoralizing so nothing here is really that complicated. If you are really experienced you might find this too easy but hopefully they are at least fun!

You do not need to do extensive fuzzing - in some cases you might need to do some automated requests and it will be mentioned in the description of the challenge.

Why this moved off AWS

All of this originally lived in my AWS account - a few small API services, a Lex bot and a Cognito user pool. It worked fine, but it never really stopped being a thing I had to think about. There was always some resource I wanted to move, some cost I was keeping an eye on, some part of it that needed a bit of attention. Eventually I took it all down "temporarily" so I could reorganize the account and, well, you saw how that went.

The annoying part is that one of my actual goals here was to build something I could just leave running. I wrote a whole thing at the end of last year about how automation gets quietly abandoned once the maintenance burden outgrows whatever value it was providing. Turns out I am not especially immune to my own material.

So rather than promising myself I would be more disciplined about it this time, I got rid of the maintenance entirely. I know myself.

The whole thing is now one Cloudflare Worker. A single JavaScript bundle - no servers, no database, no storage, no queues, nothing that persists between requests at all. Every challenge is request in, response out. It runs on the free tier, so there is genuinely nothing here to patch, restart, or pay for, which means "just leave it up" is actually achievable this time instead of being a thing I say optimistically.

Usefully this keeps the original constraint intact - there is nothing you can break here for anyone else. There are no shells to get. If something looks like it is running a command for you it is faking it, pretty convincingly, against a handful of hardcoded files.

The tradeoff is that two of the old challenges didn't make it. The Lex chatbot and the Cognito registration one were both about AWS specifically, so there was no way to bring them along without bringing along the exact thing I was trying to get rid of. I liked those ones, so I might revisit them if I find a way to host that sort of thing that doesn't slowly bleed money.