The skip_create_if_exists flag is available only for the following
tokens:
- dns
- http
- aws-id
- azure-id
- slack-api
- mysql-dump
- wireguard
You may be using scripts to mass deploy canarytokens to your environment. Sometimes these scripts can fail or be aborted midway through token creation, resulting in only a subset of the intended tokens being created. If you rerun the script, all the tokens will be created again, meaning tokens created from the first run will be duplicated. The skip_create_if_exists parameter helps mitigate this issue.
Example
Example scenario
Suppose a script is deployed which automatically creates a DNS canarytoken each time an employee starts their machine.
curl $CONSOLE_URL/api/v1/canarytoken/create \
-d auth_token=$API_KEY \
-d flock="flock:default" \
-d memo="hostname placed in CEOs browser history" \
-d kind="dns"The response contains the canarytoken as well as a url you may drop for attackers to find.
"canarytoken": {
"canarytoken": "d0yxprcqi0t0a7xjkrwdq37pr",
...
"flock": "flock:default",
"memo": "hostname placed in CEOs browser history",
"kind": "dns",
"url": "http://f4786ccc5b77.o3n.io/content/d0yxprcqi0t0a7xjkrwdq37pr/image.gif"
}Great! You drop the url somewhere on the users machine (such as there browser history) and you call it a day. If an attacker gets on the users laptop and visits all the previously browsed sites you'll get an alert.
But what happens if the user restarts their laptop?
If the user restarts their laptop, the script runs again creating a new canarytoken
"canarytoken": {
"canarytoken": "5ykk3z3zc1tpqdjjtggizqwf4",
...
"flock": "flock:default",
"memo": "hostname placed in CEOs browser history",
"kind": "dns",
"url": "http://f4786ccc5b77.o3n.io/cdn/5ykk3z3zc1tpqdjjtggizqwf4/doc.gif"
}While both canarytokens are active, and will trigger if browsed to, the console will have two canarytokens of the same kind and memo. While manageable, if the same canarytoken were created hundreds of times, this may cause a headache for the console admin.
Example fix
Let's add the skip_create_if_exists parameter to the query
curl $CONSOLE_URL/api/v1/canarytoken/create \
-d auth_token=$API_KEY \
-d flock="flock:default" \
-d memo="hostname placed in CEOs browser history" \
-d kind="dns" \
-d skip_create_if_exists="true"The first time the query is run a new canarytoken will be created. Again you will receive the token and an example url in the response.
"canarytoken": {
"canarytoken": "d0yxprcqi0t0a7xjkrwdq37pr",
...
"flock": "flock:default",
"memo": "hostname placed in CEOs browser history",
"kind": "dns",
"url": "http://f4786ccc5b77.o3n.io/content/d0yxprcqi0t0a7xjkrwdq37pr/image.gif"
}If the user restarts their laptop, the script will run again, and you'll receive a response like the one below
"canarytoken": {
"canarytoken": "d0yxprcqi0t0a7xjkrwdq37pr",
...
"flock": "flock:default",
"memo": "hostname placed in CEOs browser history",
"kind": "dns",
"url": "http://f4786ccc5b77.o3n.io/content/d0yxprcqi0t0a7xjkrwdq37pr/doc.gif"
}Notice the canarytoken d0yxprcqi0t0a7xjkrwdq37pr is the same as the first one! In this case, the console has seen that the request set skip_create_if_exists and that previously a canarytoken with matching flock, memo, and kind parameters were created. The console skips creating a new token, and instead returns the previously created matching token. Even though the script has run twice, the console has only generated a single canarytoken.
You may notice the url is different: doc.gif vs
image.gif. We regenerate
the url each time, but the token d0yxprcqi0t0a7xjkrwdq37pr matches in both
cases.
How does the console match tokens?
How a console matches tokens is dependent on the token kind. The table below describes which fields are matched per kind.
| Token kind | Matching parameters |
| dns | flock, memo, custom_domain |
| http | flock, memo, custom_domain, browser_scanner_enabled |
| aws-id | flock, memo |
| azure-id | flock, memo, azure_id_cert_file_name |
| mysql-dump | flock, memo, custom_domain, industry |
| wireguard | flock, memo |
All fields must match for the console to consider two tokens matching. A console will not match or match to a token that has an expiry set. If a parameter has not been set the console will assume the default value.