Ae1
- Category
- analysis-evasion
- Confidence
- 100% confidence
- Finding
Referenced artifact was not completely inspected
- Content
md intent routes, the optional resource, and generated Canonry `SKILL.md` files.
Security audit
Security checks for vulnerabilities and agentic risk
This is a coherent Canonry operations guide with broad, sensitive integrations, but the risky actions are disclosed and generally bounded by approval and server-side permission checks.
Install this only if you intend to operate Canonry. Use read-only or stored-only modes where possible, keep ~/.canonry/config.yaml and token/key files private, do not paste secrets into chat, and require explicit approval before writes, ad-spend actions, schedules, public webhooks, Cloudflare route changes, or WordPress content changes.
Referenced artifact was not completely inspected
intent routes, the optional resource, and generated Canonry `SKILL.md` files.
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).
uses `GET /projects/:name/content/dismissals`; dismiss uses `POST` with
`targetRef` and optional `addressedUrl` and `note`. Re-dismissing updates those
optional values and the dismissal time. Restore uses
`DELETE /projects/:name/content/dismissals/:targetRef` and returns HTTP 204; CLI and
MCP acknowledge it as `{ targetRef, restored: true }`. A missing record returns
the API's not-found error.
Skill selects an external model or provider that may use a different account or billing plan than the operator expects. Undisclosed model switches can cause unexpected cost or quota consumption.
cnry settings # show config: providers, apiUrl, db path
cnry settings --format json
cnry settings reload-providers --format json # apply the server's saved provider config
cnry settings provider gemini --api-key <KEY> --model gemini-flash-latest
cnry settings provider openai --max-per-day 1000 --max-per-minute 20
cnry settings provider perplexity --api-key <KEY> --model fast
cnry settings provider muse --api-key <KEY> --model muse-spark-1.3
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.
cnry bing set-site https://example.com/
Get API key from: https://www.bing.com/webmasters/ → Settings → API Access
### Check connection and coverage
```bash
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
in a group. `cnry --help --format json` and `cnry ga --help --format json` provide
the same discovery output. The catalog includes access, flags, dry-run support and
supported rolling windows. Contextual help prints `Access: stored`, `Access: live`
or `Access: write`; live means the command calls a provider now, while write means
it changes server or local state. `--trace` reports the response access header for
API calls. Help is local and does not contact the server.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# One contract joins business meaning to the selected Google Ads action and GTM graph.
cnry conversion-tracking contracts <project> --format jsonl
cnry conversion-tracking contracts get <project> <contract-id>
cnry conversion-tracking contracts create <project> --input contract.json
cnry conversion-tracking contracts update <project> <contract-id> --input contract.json
cnry conversion-tracking contracts delete <project> <contract-id>
cnry conversion-tracking contracts integrity <project> <contract-id> --format jsonl
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
return a validation error. Inspect retention/loss counters before assuming
coverage. Use `history` for durable audit
events, with `--limit 1..500 --offset <n>` for traversal. Offset pages are not a
concurrent-write snapshot.
Google setup and telemetry default to local configuration. Pass `--target server`
to use the connected server; settings reads always describe the server.
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
**Account-credential gotcha:** API calls use your **Application Default Credentials** (`gcloud auth application-default login` → `print-access-token`), while `gcloud services enable` uses the separate **gcloud CLI account** (`gcloud config get-value account`). These can be different identities. Verify the token's real account with `curl "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=$TOKEN"` before concluding anything about access — a "wrong account" symptom is often just the two credential stores disagreeing.
### Create OAuth client credentials
1. Cloud Console → APIs & Services → **OAuth consent screen** → set up consent (External works). Add your own email under "Test users" while the app is in test mode.
2. Cloud Console → APIs & Services → **Credentials** → **+ Create Credentials** → **OAuth client ID**.
The document explicitly tells users to persist a Google OAuth client secret and per-user OAuth tokens in ~/.canonry/config.yaml, and even notes that tokens are stored there, without any warning about file permissions, encryption, OS keychain use, or secret-handling hygiene. If that file is readable by other local users, captured in backups, checked into dotfile sync, or exposed through logs/support bundles, an attacker could reuse refresh tokens or client credentials to access managed Google Business Profile data.
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
Submit URLs:
curl -X POST "https://www.bing.com/indexnow" \
-H "Content-Type: application/json; charset=utf-8" \
-d '{
"host": "example.com",
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
# 1. Create a service account in the Cloud project that hosts the Cloud Run
# service. Grant it `roles/logging.viewer`. Download the JSON key.
# 2. Connect from cnry CLI:
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
hits for the tracked site.
# 1. In the Vercel dashboard, create a token with read access to the
# target team (Settings → Tokens → Create). Note the team ID
# (Settings → General → Team ID) and the Vercel project ID
# (Project → Settings → General → Project ID).
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
CANONRY_PUBLIC_URL=https://canonry-ops.example.net
curl -sS -o /dev/null -w '%{http_code}\n' \
-X POST -H 'content-type: application/json' --data '{}' \
"${CANONRY_PUBLIC_URL%/}/api/v1/projects/<project>/traffic/cloudflare/ingest"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
# assets -> no worker. Omitting "script" is what disables it.
curl -s -X POST -H "Authorization: Bearer $CF_TOKEN" -H "Content-Type: application/json" \
--data '{"pattern":"<host>/_nuxt/*"}' \
"https://api.cloudflare.com/client/v4/zones/$ZONE/workers/routes"
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
curl -s -X POST -H "Authorization: Bearer $CF_TOKEN" -H "Content-Type: application/json"
--data '{"pattern":"/_nuxt/*"}'
"https://api.cloudflare.com/client/v4/zones/$ZONE/workers/routes"
Prefixes by framework: `/_nuxt/*` Nuxt, `/_next/*` Next.js, plus `/assets/*`,
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
curl -s -X POST -H "Authorization: Bearer $CF_TOKEN" -H "Content-Type: application/json"
--data '{"pattern":"/_nuxt/*"}'
"https://api.cloudflare.com/client/v4/zones/$ZONE/workers/routes"
Prefixes by framework: `/_nuxt/*` Nuxt, `/_next/*` Next.js, plus `/assets/*`,
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.
CANONRY_QUEUE_SMOKE_PATH="/canonry-cloudflare-queue-smoke/$(date -u +%Y%m%dT%H%M%SZ)"
curl -sS -o /dev/null -w '%{http_code}\n' \
"https://www.example.com${CANONRY_QUEUE_SMOKE_PATH}?utm_source=chatgpt"
sleep 2
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.
## What Canonry Automates
- Read and write page content, titles, slugs, and status
- Audit pages for `noindex`, missing SEO title, missing meta description, missing schema, and thin content
- Compare live vs staging for a page with `cnry wordpress diff`
- Update SEO meta when the site exposes writable REST meta fields
Skill's behavior or capabilities extend beyond its stated purpose. Scope creep allows an agent to perform actions unrelated to its documented functionality, increasing the attack surface.
Every read command queries persisted DB rows, so a stale `lastSyncedAt` means the response is stale — always check `ga status` before drawing conclusions, and re-`ga sync` if the data is older than the analysis window. Use `--only ai`, `--only social` or `--only search-landing` to refresh just one slice when iterating.
`ga search-landing-pages` reads GA4's Search Console collection, not Canonry's own GSC sync: its clicks come through the GA4 property's Search Console link and can differ from `google performance` for the same days. Active users is GA4's plain `activeUsers` from the same request, which is what GA4's report shows (not limited to Google organic sessions). Search Console data reaches GA4 about two days late, so the last days of each window are thin, exactly as in GA4. A property without a Search Console link is expected to read `unavailable` with Google's message in `error` (inferred, not yet observed from a live unlinked property); the previous snapshot stays readable beside that status.
## Google Business Profile (Local AEO)
No suspicious patterns detected.