We Put A C2 In Your Notetaking App: OffensiveNotion

A Red Teaming Science Fair Project

6 min readFeb 27, 2022


tl;dr: We realized you can use the Notion developer API to build a C2 platform. We wrote a cross-platform agent in Rust. It runs on Linux and Windows. All C2 comms traverse the Notion developer API. It’s not a world-class C2 but does have a lot of post-exploitation capabilities. We think it’s pretty cool! The code repo is here, the documentation is here. We hope you like it!

mttaggart & HuskyHacks, co-developers.

Notion is a popular notetaking application. It has lots of great features that make notetaking a snap. Some of the features we love the most include the capability to share notebooks across teams, push notes to cloud storage, build custom templates, and, in general, deck out your pages so they feel like they have lots of personality! I recommend checking it out if you’re looking for a new notetaking application.

An example of one of my notebooks within Notion

One of the features of the Notion platform is the Notion developer API. This API allows you to perform web requests that can add and change data within your Notion notebook. This is accomplished via a standard set of API web request methods. This allows you to create pages, add blocks to pages, and do just about anything else that you can do with the Notion app itself.

This is a story about how we (mttaggart and HuskyHacks) built an entire C2 platform around the Notion developer API.


In mid January 2022, I was examining the Notion application and noticed that by adding a file to your own private notebook, you get access to an S3 AWS resource link. You can then use this link for nefarious purposes like malware delivery. Read more about it here:

The long and short of it was that after speaking to the Notion developers, they informed me that this was intended functionality for the platform. Unlimited S3 AWS phishing links! Sweet!

This was the genesis of our interest in Notion for red team operations.

Shortly after this, Taggart examined the Notion developer API. Taggart is an absolute wizard when it comes to web application shenanigans, so I watched on in awe as he formed a Python script to programmatically read blocks, evaluate their contents, perform some kind of command as a result of those contents, and post the results to a specified Notion page in his notebook. We topped it off with my personal favorite feature: the command was evaluated if and only if there was a 🎯 emoji at the end. This led to a code snippet that I believe deserves to be in the Smithsonian as a relic of landmark technology:

This was the spark of inspiration that caused us to ask:

  • If you can programmatically read from and write to a Notion page using the Notion API in a completely legitimate fashion…
  • … and the Notion API does not care where these requests come from as long as they are formatted correctly…
  • … and the logic for reading from and endpoint, evaluating something from that endpoint, carrying out a command, posting the results, and waiting for another set of instructions is basically the definition of how a C2 agent functions…

… then could we make a C2 that uses the Notion platform to control an agent?

Narrator: Yes, indeed, they could.

Coding began in mid January. The first attempt was to make an agent in Nim. This failed (apparently there are some bugs in Nim’s async implementation). Then, we decided to do the unthinkable and implement the agent in Rust. I had never written a single line of Rust in my life so this was quite the rollercoaster for me. But we were able to have a working proof of concept agent completed within a few weeks and continued to develop post-exploitation features.

The “Listener” page with multiple agent sessions.

As of the end of February 2022, OffensiveNotion is in version 1.0.0 “Iron Age.” We call it this because every time we thought of a cool feature to implement, having drawn inspiration from other C2s we love like Cobalt Strike and Empire, we’d try to remind ourselves that we were still in the Stone Age of this project’s development. We settled on a core set of features for the evolution into the Iron Age. Someday we’ll hit the Space Age and send a rocket ship to Alpha Centauri to achieve the Space Race victory condition.

Design Philosophy

We drew up plans for what MUST, SHOULD, and COULD be implemented in Iron Age. This included the absolute necessities (ability to run commands, sleep time adjustment, a reasonable amount of error handling so the agent didn’t explode randomly) as well as some more sophisticated features (persistence, elevation mechanisms). Many things didn’t make it into V1.0.0. And that’s OK! More development is on the way.

One very interesting design space limitation was the complete inflexibility of the C2 server. Think about how any other C2 works. The developer has complete control over the design of both the agent and the server and can modify each to better suit the other. We didn’t have that option. Neither of us have any interest in applying for a Notion Dev Team position in the near future (though they are lovely people), so we couldn’t make any changes to how the server interacted with the agent. We could only form the agent to fit the server. This was an interesting design limitation, but proved to be a fun challenge to work through. In short, we needed to focus on granting robust command evaluation capabilities to the agent in order to do all of the C2 heavy lifting.

Learning how to do this in Rust was a doozy for me! In Taggart’s words, “Rust is the old school martial arts instructor that used to hit my legs with a pole when my stance was not low enough.” I went several rounds with the Rust compiler night after night during this project and I can say that is 100% true. But I have no doubt it has made me into a better developer.

An example of the handling that allows the agent to evaluate commands from the Notion blocks.

But what the C2 server lacks in flexibility, it more than makes up for in terms of stealth capabilities. When all is said and done, the process running on your target is receiving orders and dispatching results to and from the legitimate Notion developer API. You inherit all of the hard work the Notion devs have put in that make this API secure, including encrypted comms and a legitimate TLS certificate.

Nothing to see here, blue teamers. Move along.

We wrote a whole section of the wiki on OPSEC. Check it out here if you’re interested:

In short, this is a LOTS (living off trusted sites) goldmine and makes for incredibly sneaky C2 capacities.

Closing Thoughts

Adam Savage once said “Every Tool’s A Hammer.” We here at HuskyTaggart Works, LLC*, like to believe “Every Tool’s A C2.” All it takes is a little creativity and some elbow grease!

Please see the code repository and documentation if you are interested in learning more:

Thank you for reading! We hope you enjoyed this article.

*not a legitimate LLC…. yet.

edit 2/27: typo

edit 2/28: embeds instead of links