Skip to content

Category: CI/CD Security

Canary Token is great…but beware of a flaw when using Thinkst’s free service for Canary AWS token


Canary Token is a great idea for early detection of possible intrusion in your system.

But be careful when you are using the free service from Thinkst Canary ( to generate Canary AWS tokens. You shouldn’t use it for real life production.

A threat actor may notice a common pattern in the AWS access key id (generated from Thinkst Canary) and avoid triggering your honeypot detection.

AWS Access Key ID Format

Aidan Steele wrote an in-depth article on AWS Access Key ID format. Highly recommend to read it.

Things to note from Aidan’s article:

  • The first 4 chars of the AWS Access Key will be indicate the resource types (
  • The next 8 chars of the access key will be mapped to a specific AWS account.

We can get the AWS account id from the access key by using the aws-cli

$ aws sts get-access-key-info --access-key-id <<ACCESS_KEY_ID>> --query Account --no-cli-pager

Flaws from the free service

Let’s generate a few Canary tokens from

aws_access_key_id = AKIAYVP4CIPPxxxxxxxU
aws_secret_access_key = xxxxxxxx
output = json
region = us-east-2
aws_access_key_id = AKIAYVP4CIPPxxxxxxxW
aws_secret_access_key = xxxxxxxxx
output = json
region = us-east-2

As you can see from the two generated Canary token, the four chars of the access key id show that this is an access key. Then the next crucial pattern (next 8 chars) will expose the information that this access key belongs to the AWS account from the free Canary token service.

A smart threat actor will detect this pattern and avoid using it. As a result, your Canary Token honeypot will likely to fail.


  • Avoid using Canary Token services which provide predictable access key pattern. A threat actor can identify the pattern and avoid triggering the canary token.
  • Canary Token is one of the detectors that we should use, but beware of confirmation biases (Canary token not triggered does not mean there is no intrusion).

GH Actions Misconfiguration – causing Command Injection

Suppose you have a Github Actions script like below:

The script will be triggered when a new issue comment is added to the issue or a comment is edited.

name: GitHub Actions Demo
    types: [created, edited]
    runs-on: ubuntu-latest
      - run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
      - run: echo "🐧 This job is now running on a ${{ runner.os }} server hosted by GitHub!"
      - run: echo "🔎 The name of your branch is ${{ github.ref }} and your repository is ${{ github.repository }}."
      - run: echo ${{ github.event.comment.body }}

Notice that ${{ github.event.comment.body }} is used in the run step directly? This makes the script vulnerable to Command Injection. Why?

Read this:

In this context, someone can inject commands to the GH Action script by adding their payload to the issue comment. The GH Action script is triggered every time there is a new issue comment.

Did you notice we can run echo bye? This is just a simple example but worse scenario can be reverse-shell (if you are using self-hosted GH Runners) or secrets theft.

See that we can echo bye

You can even attack in a stealth mode by deleting the comment immediately once the workflow is triggered.

How to prevent the issue?

Set the github context data in env variable before you use it in the run

      - env: # Add this
          BODY: ${{ github.event.comment.body }} # Add this
        run: echo "$BODY"

Add a new comment that contains a payload:

You can see the script is interpreting the comment body as string rather than interpolating it as a command to execute.