Security at AdWitch AI
How AdWitch protects your Meta ad accounts and data: token encryption, the exact Meta permissions we request, team isolation, sub-processors, retention and deletion, and how to report a vulnerability.
Last updated:
AdWitch operates on your Meta ad accounts with the permissions you grant it. That makes the handling of access tokens and account data the core of the product, not a side concern. This page describes the controls that actually exist in the platform today — nothing aspirational. When a control changes, this page and the changelog change with it.
Access tokens and secrets
- Meta access tokens are encrypted at rest with AES-256-GCM (random IV, authenticated tag) before they are written to the database. The encryption key is derived from a secret that lives only in the application environment, separately from the database and its backups — a database dump alone does not expose tokens.
- Tokens are never shown back in the interface or the API after connection; only their state (valid, expiring, which permissions they carry) is displayed.
- Every call to the Meta Graph API is signed with an
appsecret_proof, so a leaked token cannot be replayed from outside our servers. Ad accounts are connected only through Facebook Login for Business with the AdWitch app: every token is issued by Meta to our app, and on connection it is inspected via Meta’sdebug_tokenendpoint to record the app it belongs to, whether it is valid, its type and expiry and which permissions it carries. We do not accept pasted or imported tokens. - Passwords are stored as bcrypt hashes. Optional two-factor authentication (TOTP, 6 digits / 30 seconds) is available for every account; the TOTP secret is stored encrypted with the same scheme as tokens.
- A password reset revokes every existing session of the account. Individual sessions can also be revoked server-side.
What we ask Meta for, and why
When you connect through “Continue with Facebook”, AdWitch requests these permissions and no others:
| Permission | Used for |
|---|---|
ads_read | Reading campaigns, ad sets, ads, insights and delivery status for reports, monitoring and the agent’s analysis. |
ads_management | Creating and editing campaigns, budgets, audiences, creatives and automated rules when you ask the agent to — or when Autopilot is switched to a mode that may act. |
business_management | Listing the Business Manager portfolios and ad accounts you can access, so you can pick which ones to connect. |
pages_show_list, pages_read_engagement | Listing the Pages (and linked Instagram accounts) an ad can be published from, and reading comments for moderation. |
pages_manage_ads | Publishing ads on behalf of a Page you administer. |
public_profile | Identifying the Facebook user who made the connection (needed to honour Meta’s deauthorisation and data-deletion callbacks). |
Read-only work (reports, monitoring) needs only ads_read; the platform records which permissions a token actually carries and refuses write actions when ads_management is missing, instead of failing half-way.
Team isolation and roles
- Every ad account, campaign, creative, conversation and file belongs to exactly one team. Every database query in the API is scoped to the team of the signed-in session; there is no cross-team endpoint.
- Roles inside a team are Owner, Admin, Manager, Analyst and Viewer. Connecting ad accounts, changing Autopilot settings and billing are limited to the higher roles; Viewer and Analyst cannot change anything in Meta.
- Generated creatives and attachments are stored in Cloudflare R2. Stable media links are served through the API with team access checks; short-lived signed links allow authorized browsers and providers to read media. Files from before this move are being copied from the Bunny.net CDN into R2; the Bunny zone is deleted once the copy is verified.
- AdWitch staff can look into a customer workspace only through an explicit support session that is flagged as such in every request; such sessions are barred from administrative functions.
Application and network controls
- All traffic is served over HTTPS. The API sends strict security headers (HSTS, Content-Security-Policy, frame protection).
- State-changing requests are protected against CSRF: the API requires a same-site request or an allow-listed origin.
- Sign-in, registration, AI endpoints and the API as a whole are rate-limited per client.
- Outbound requests initiated from user input (fetching an image URL, a webhook target) go through an SSRF-safe fetcher that resolves DNS once, rejects private and link-local ranges, pins the validated address and re-validates every redirect.
- Incoming webhooks are authenticated before any processing: Meta and Stripe deliveries are verified by signature (Meta callbacks additionally for freshness and replay); Higgsfield sends no signature, so its callback URL carries a secret token derived from our app secret and any request without the right token is rejected.
- The chat agent’s write actions on Meta go through a server-side confirmation gate: the tool arguments are validated on the server and the action executes only after your confirmation in the conversation, per turn and per tool.
Sub-processors
We share data with the following providers, only to the extent needed for the feature you use:
| Provider | Purpose | Data involved |
|---|---|---|
| Meta Platforms | The advertising platform itself | Everything you ask the agent to read or change in your ad accounts |
| Anthropic | Language model behind the agent | Conversation text, campaign metrics and creative texts included in the conversation |
| Higgsfield | Image and video generation | Prompts and reference images you provide for creatives |
| Cloudflare R2 | Object storage for generated and uploaded media | Creative files |
| Bunny.net | Older media from before the move to R2 (being retired) | Creative files |
| Stripe | Card payments | Payment details (handled by the provider; AdWitch stores no card numbers) |
| Resend | Transactional e-mail | E-mail address, verification codes, notifications |
| Telegram | Optional notifications and support bot | Telegram user id and the messages you choose to receive |
The application database and cache run on servers we operate ourselves; they are not shared with other tenants’ workloads.
Retention and deletion
- Meta callbacks are honoured automatically. When you remove AdWitch from your Facebook settings (deauthorisation) or file a data-deletion request through Meta, the platform revokes the stored access tokens and disconnects every ad-account connection made by that Facebook user, across all teams. Deletion requests get a confirmation code and a status page; status records are kept for 90 days.
- Account and workspace deletion follows the Data Deletion policy: a request to privacy@adwitch.ai is fulfilled within 30 days and removes profile data, ad-account settings and tokens, campaign and creative history, analytics, sessions and knowledge-base files.
- Removing an ad account inside the app deletes its connection record, including the stored token, immediately.
- Payment records are retained as long as tax and accounting law require, without card data.
Responsible disclosure
If you believe you have found a security vulnerability in AdWitch, please e-mail security@adwitch.ai with the steps to reproduce. The same contact is published in /.well-known/security.txt.
- We acknowledge reports within 3 business days and keep you informed until the issue is resolved.
- Please give us a reasonable time to fix the issue before public disclosure, do not access data that is not yours, and do not run automated scanners against production or disrupt the service.
- We will not pursue legal action against researchers who follow these rules in good faith. There is currently no paid bounty programme; we credit reporters in the changelog on request.
Compliance certifications (SOC 2, ISO 27001) are not held at this time; we will announce any audit on this page.
Questions about this page: security@adwitch.ai. Policy URL: https://adwitch.ai/security