# Website Security Headers & TLS Audit (`helveticlabs/security-audit`) Actor

Grade any website's security from A+ to F: HTTPS redirect, HSTS, CSP, clickjacking protection, cookie flags, TLS certificate expiry, security.txt and e-mail spoofing protection (SPF, DMARC). Passive and polite.

- **URL**: https://apify.com/helveticlabs/security-audit.md
- **Developed by:** [Helvetic Labs](https://apify.com/helveticlabs) (community)
- **Categories:** Developer tools, SEO tools, Automation
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 domain auditeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Website Security Headers & TLS Audit

Grade the security of up to 5,000 websites per run from **A+ to F**, with a concrete fix for
every finding. One run checks HTTPS and the HTTP to HTTPS redirect, the security headers
(HSTS, CSP, X-Frame-Options and more), cookie flags, the SSL/TLS certificate and its expiry,
`security.txt`, and the domain's e-mail spoofing protection (SPF and DMARC). For agencies,
security teams, developers and IT administrators who want a quick, passive and repeatable
security check of many domains.

### What is Website Security Headers & TLS Audit?

It is a bulk security headers checker, SSL certificate checker and SPF/DMARC checker in one
Actor. You enter domains or URLs; for each host it looks at what every browser and every mail
server can see anyway, scores the web security from 0 to 100, turns the score into a grade
from A+ to F, scores the e-mail protection separately, and lists every check as pass, warn,
fail or info, with a short fix for each problem.

The audit is passive. Per domain it requests the home page over HTTPS and over HTTP without
reading the page body, fetches `/.well-known/security.txt`, makes one TLS handshake and runs a
few DNS lookups. There are no port scans, no probing of paths, no login attempts and no load
on the site. It respects `robots.txt` and identifies itself with an honest user agent.

### What does it check?

**Web security (score 0 to 100, graded A+ to F):**

- **HTTPS:** the home page answers over HTTPS with a valid certificate.
- **HTTP to HTTPS redirect:** `http://` ends on an HTTPS URL.
- **HSTS (`Strict-Transport-Security`):** present, `max-age`, `includeSubDomains` and
  `preload`.
- **Content-Security-Policy:** present, whether it allows inline scripts (`'unsafe-inline'`
  without nonces, hashes or `'strict-dynamic'`), whether it allows `'unsafe-eval'`, and
  whether it has `frame-ancestors`.
- **Clickjacking protection:** CSP `frame-ancestors` or `X-Frame-Options: DENY` or
  `SAMEORIGIN`.
- **`X-Content-Type-Options: nosniff`**, **`Referrer-Policy`** and **`Permissions-Policy`**.
- **Cookie flags:** how many cookies the home page sets, and how many lack `Secure`,
  `HttpOnly` or `SameSite`. Counts only, never cookie names or values.
- **Software version disclosure:** whether `Server` or `X-Powered-By` shows a version number.
- **TLS and SSL certificate:** TLS version, certificate issuer, expiry date and days left.
- **`security.txt` (RFC 9116):** published at `/.well-known/security.txt` with a `Contact`
  field, whether it has an `Expires` field, and whether it is expired.

**E-mail spoofing protection (scored 0 to 100 separately):**

- **SPF:** present, exactly one record, and how it ends (`-all`, `~all`, `?all`, `+all`).
- **DMARC:** present, policy (`none`, `quarantine`, `reject`), `pct`, whether aggregate
  reports are requested (yes or no, never the address), and for subdomains the policy they
  inherit from a parent domain.
- **MX:** the number of mail servers.

**Also reported:**

- **CAA records:** whether the domain restricts which certificate authorities may issue
  certificates for it, and which ones.

### Use cases

- **Client audits for agencies:** run all client domains at once, sort by grade and send each
  client the findings with their fixes.
- **Security reviews of your own domains:** find the forgotten marketing site without HSTS,
  the subdomain with an expiring certificate or the brand domain without DMARC.
- **SSL certificate expiry monitoring:** schedule a daily run and alert on `tls.days_left`
  below your threshold, before visitors see a certificate warning.
- **E-mail spoofing checks:** check SPF and DMARC across a portfolio of domains, including
  parked domains that should publish `v=spf1 -all` and a DMARC reject policy.
- **Release checks:** after a deployment, confirm that the security headers are still set
  and that the grade did not drop.
- **Supplier and partner overviews:** get a quick, passive view of the public security
  posture of the domains you work with, where you are allowed to check them.
- **Tracking progress:** run the same list every month and compare the scores over time.

### How to use Website Security Headers & TLS Audit

1. Open the Actor in Apify Console (click **Try for free** or **Start** on this page).
2. Enter your domains or URLs in **Domains or URLs**, one per line.
3. Keep **Check e-mail DNS (SPF, DMARC)** on to get the e-mail score, or turn it off to audit
   only the web side.
4. Optionally change the timeout.
5. Set a **maximum cost per run** in the run options if you want a hard spending limit.
6. Click **Start**. When the run is done, open the **Output** tab, sort by grade or score, and
   download the results as JSON, CSV, Excel, XML or HTML.
7. Create a **Schedule** to repeat the audit daily, weekly or monthly.

### Input

| Field | Type | Default | What it does |
| --- | --- | --- | --- |
| `domains` | array of strings | (required) | Domains (`example.com`) or URLs (`https://www.example.com/page`). |
| `checkEmailDns` | boolean | `true` | Also check SPF, DMARC and MX of the domain. |
| `timeoutSecs` | integer, 5 to 60 | 15 | How long to wait for each response, in seconds. |

Tips:

- **One host per line.** From a URL only the host name is used, and the home page of that host
  is audited; the path is ignored. `example.com` and `www.example.com` are different hosts
  and are audited (and charged) separately, so enter the one your visitors use, or both if
  you want to compare.
- **E-mail checks use the domain without `www.`** For `www.example.com`, SPF and DMARC are
  looked up for `example.com`.
- **IP addresses** can be audited for HTTPS and headers; the e-mail and CAA checks are then
  skipped.
- **Limits:** up to 5,000 entries per run; further entries are ignored. Exact duplicates are
  audited once.
- **API input:** besides strings, you can pass objects like `{"url": "https://example.com/"}`.

Example input:

```json
{
  "domains": ["example.com", "https://www.example.org/", "shop.example.net"],
  "checkEmailDns": true,
  "timeoutSecs": 15
}
```

### Output

One dataset item per domain, in the order of your input. A complete example:

```json
{
  "input": "example.com",
  "domain": "example.com",
  "checked_at": "2026-10-18T09:00:00Z",
  "https": {"ok": true, "status": 200, "final_url": "https://example.com/", "http_version": "HTTP/1.1", "error": ""},
  "http_to_https": true,
  "tls": {"ok": true, "version": "TLSv1.3", "issuer": "Let's Encrypt", "valid_until": "2027-01-05", "days_left": 79, "error": ""},
  "headers": {
    "hsts": {"present": true, "max_age": 31536000, "include_subdomains": true, "preload": false},
    "csp": {"present": false, "frame_ancestors": false, "unsafe_inline_scripts": false, "unsafe_eval": false},
    "x_frame_options": "sameorigin",
    "x_content_type_options": true,
    "referrer_policy": "strict-origin-when-cross-origin",
    "permissions_policy": false,
    "server_version_disclosed": false
  },
  "cookies": {"count": 2, "without_secure": 0, "without_httponly": 1, "without_samesite": 1},
  "security_txt": {"present": true, "has_contact": true, "has_expires": true, "expired": false},
  "error": "",
  "score": 75,
  "grade": "B",
  "email": {
    "domain": "example.com",
    "mx_count": 2,
    "spf": {"present": true, "records": 1, "all": "-all"},
    "dmarc": {"present": true, "policy": "quarantine", "pct": 100, "reports": true, "inherited_from": null, "invalid": false}
  },
  "email_score": 95,
  "caa": {"present": true, "issuers": ["letsencrypt.org"]},
  "findings": [
    {"check": "http_redirect", "status": "pass", "detail": "HTTP redirects to HTTPS.", "fix": ""},
    {"check": "hsts", "status": "pass", "detail": "HSTS max-age 31536000 s.", "fix": ""},
    {"check": "csp", "status": "fail", "detail": "No Content-Security-Policy header.", "fix": "Add a Content-Security-Policy, starting with default-src 'self'."},
    {"check": "framing", "status": "pass", "detail": "The site cannot be framed by others.", "fix": ""},
    {"check": "nosniff", "status": "pass", "detail": "X-Content-Type-Options: nosniff is set.", "fix": ""},
    {"check": "referrer", "status": "pass", "detail": "A privacy-friendly Referrer-Policy is set.", "fix": ""},
    {"check": "permissions", "status": "warn", "detail": "No Permissions-Policy.", "fix": "Add a Permissions-Policy that turns off unused features (camera, microphone, geolocation)."},
    {"check": "cookies", "status": "warn", "detail": "Some cookies lack HttpOnly or SameSite.", "fix": "Set HttpOnly and SameSite on every cookie scripts do not need."},
    {"check": "disclosure", "status": "pass", "detail": "No software versions in the headers.", "fix": ""},
    {"check": "tls", "status": "pass", "detail": "TLSv1.3, certificate valid until 2027-01-05.", "fix": ""},
    {"check": "security_txt", "status": "pass", "detail": "security.txt is published.", "fix": ""},
    {"check": "spf", "status": "pass", "detail": "SPF record ends with -all.", "fix": ""},
    {"check": "dmarc", "status": "pass", "detail": "DMARC policy quarantine.", "fix": ""}
  ]
}
```

An entry that is not a public domain is listed like this, free of charge:

```json
{"input": "typo-domain.example", "domain": null, "grade": null, "error": "dns_error"}
```

#### Output fields

| Field | Type | Meaning |
| --- | --- | --- |
| `input` | string | Your entry as given (trimmed, at most 500 characters). |
| `domain` | string or null | The audited host name; `null` when the entry could not be audited. |
| `checked_at` | string | When the domain was audited, in UTC. |
| `https.ok` | boolean | The HTTPS home page answered (status below 500) and ended on an HTTPS URL. |
| `https.status` | integer or null | Status code of the HTTPS home page. |
| `https.final_url` | string or null | Where the HTTPS home page ends up after redirects. |
| `https.http_version` | string or null | HTTP version of that answer. |
| `https.error` | string | Why HTTPS did not work, for example `tls_error` or `timeout`. |
| `http_to_https` | boolean or null | `http://` ends on an HTTPS URL; `null` when the HTTP request failed (scored as no redirect). |
| `tls.ok` | boolean | The TLS handshake on port 443 worked and the certificate is valid for the host. |
| `tls.version` | string or null | Negotiated TLS version, for example `TLSv1.3`. |
| `tls.issuer` | string or null | The certificate issuer's organization (or common name). |
| `tls.valid_until` | string or null | Certificate expiry date (YYYY-MM-DD). |
| `tls.days_left` | integer or null | Days until the certificate expires. |
| `tls.error` | string | Why the handshake failed, for example a certificate verification message. |
| `headers.hsts` | object | `present`, `max_age` (seconds), `include_subdomains`, `preload`. |
| `headers.csp` | object | `present`, `frame_ancestors`, `unsafe_inline_scripts`, `unsafe_eval`. |
| `headers.x_frame_options` | string or null | The `X-Frame-Options` value in lower case. |
| `headers.x_content_type_options` | boolean | `X-Content-Type-Options` is `nosniff`. |
| `headers.referrer_policy` | string or null | The effective `Referrer-Policy` value. |
| `headers.permissions_policy` | boolean | A `Permissions-Policy` header is set. |
| `headers.server_version_disclosed` | boolean | `Server` or `X-Powered-By` contains a version number. |
| `cookies` | object | `count`, `without_secure`, `without_httponly`, `without_samesite` for the cookies set by the final response of the HTTPS home page. |
| `security_txt` | object | `present` (has a Contact field), `has_contact`, `has_expires`, `expired` (`null` when there is no readable Expires date). |
| `error` | string | Empty, or why the domain could not be audited (`invalid_url`, `not_public_address`, `dns_error`, `blocked_by_robots`, `robots_unavailable`, `internal: ...`). |
| `score` | integer or null | Web security score 0 to 100; `null` when `robots.txt` did not allow reading the headers. |
| `grade` | string or null | A+, A, B, C, D or F; `null` as for `score`. |
| `email.domain` | string | The domain used for the e-mail checks (without `www.`). |
| `email.mx_count` | integer or null | Number of MX records; `null` when no DNS resolver answered. |
| `email.spf` | object | `present`, `records` (number of SPF records), `all` (how the record ends). |
| `email.dmarc` | object | `present`, `policy`, `pct`, `reports`, `inherited_from` (the parent domain whose record applies), `invalid` (more than one DMARC record). |
| `email_score` | integer or null | E-mail protection score 0 to 100; `null` when the DNS answers were not available. |
| `caa` | object | `present` and `issuers` (up to 10 certificate authorities allowed to issue). |
| `findings` | array | Every check as `{check, status, detail, fix}`; `status` is `pass`, `warn`, `fail` or `info`. |

The `email` and `email_score` fields are left out when `checkEmailDns` is off.

#### Dataset view

The **Overview** table shows `domain`, `grade`, `score`, `email_score`, the certificate expiry
date, the findings and `error`, so you can sort a whole portfolio by grade.

### How the score works

| Check | Points | Partial points |
| --- | --- | --- |
| HTTP redirects to HTTPS | 10 | |
| HSTS with `max-age` of at least 180 days (15,552,000 s) | 15 | 8 for a shorter `max-age` |
| Content-Security-Policy without inline scripts | 15 | 8 when it allows inline scripts |
| Clickjacking protection (`frame-ancestors` or `X-Frame-Options`) | 10 | |
| `X-Content-Type-Options: nosniff` | 10 | |
| Strict `Referrer-Policy` | 5 | |
| `Permissions-Policy` | 5 | |
| All cookies with `Secure`, `HttpOnly` and `SameSite` (or no cookies) | 10 | 5 when all have `Secure` but some lack the others |
| No software versions in `Server` or `X-Powered-By` | 5 | |
| TLS 1.2 or 1.3 and at least 14 days left on the certificate | 10 | 5 when TLS works but the version is older or the certificate expires within 14 days |
| `security.txt` with Contact, not expired | 5 | |

A strict `Referrer-Policy` is one of `no-referrer`, `same-origin`, `strict-origin`,
`strict-origin-when-cross-origin`, `origin` or `origin-when-cross-origin`. If HTTPS does not
work at all, the score is 0.

| Score | Grade |
| --- | --- |
| 95 to 100, with HSTS `includeSubDomains` | A+ |
| 85 to 94 (or 95 and more without `includeSubDomains`) | A |
| 70 to 84 | B |
| 55 to 69 | C |
| 40 to 54 | D |
| below 40, or no working HTTPS | F |

**E-mail score:** one SPF record gives 30 points, plus 20 when it ends with `-all` or 10 with
`~all`. A DMARC record gives 30 points, plus 20 for `p=reject` or 15 for `p=quarantine`. More
than one SPF record counts as none, because receivers ignore them; more than one DMARC record
is reported as `invalid` and scores like no DMARC record.

### How much does it cost?

This Actor uses pay-per-event pricing: you pay **USD 0.01 per domain audited** (USD 10 per
1,000 domains), plus Apify's standard **actor start event of USD 0.00005 per run**. With
pay-per-event pricing the platform usage of the run is included in these prices.

| Domains audited | Domain events | Actor start | Total |
| --- | --- | --- | --- |
| 10 | USD 0.10 | USD 0.00005 | USD 0.10005 |
| 100 | USD 1.00 | USD 0.00005 | USD 1.00005 |
| 1,000 | USD 10.00 | USD 0.00005 | USD 10.00005 |
| 5,000 (the maximum per run) | USD 50.00 | USD 0.00005 | USD 50.00005 |

What is charged and what is free:

- **Charged:** every domain the audit contacted, whatever the result, including a domain
  whose `robots.txt` did not allow reading the headers (the e-mail checks still run).
- **Free:** entries that are not valid domains or URLs, hosts that do not resolve, hosts on
  non-public addresses, and entries that failed with an internal error. They are listed with
  their error code but not charged.

Set a **maximum cost per run** and the audit respects it: if your limit covers fewer domains
than your list has, only the first ones are audited. Apify's free plan includes monthly
platform credit, which you can use to try the Actor.

### Tips and best practices

- **Start with the fails.** Each finding has a `fix`. Fixing the `fail` items first gives the
  biggest score gains: CSP and HSTS are worth 15 points each.
- **Aim for A+ deliberately.** A+ needs at least 95 points and HSTS with `includeSubDomains`.
  Add `includeSubDomains` only when every subdomain serves HTTPS.
- **Monitor certificates.** Schedule a daily run and alert when `tls.days_left` is low; the
  TLS check already turns to `warn` below 14 days.
- **Check parked domains too.** Domains that never send mail should publish `v=spf1 -all` and
  a DMARC record with `p=reject`; the e-mail score shows which ones do not.
- **Compare apex and www.** Headers often differ between `example.com` and
  `www.example.com`; audit both when in doubt.
- **Allow the audit on your own site.** It obeys `robots.txt` rules for the product token
  `HelveticLabs-WebCheck`. If your site blocks bots, allow that token to get a grade.

### Limitations

- **It is not a penetration test.** It shows common best practices that are visible from
  outside, not vulnerabilities in the application.
- **Home page only.** Headers and cookies are read from the home page of each host; other
  pages may send different headers.
- **robots.txt is respected.** When `robots.txt` disallows the home page, or answers with a
  server error, the headers are not read: `score` and `grade` are `null`, and the e-mail
  checks still run.
- **`security.txt`** is read only from `/.well-known/security.txt`, must be served as
  `text/plain` and is read up to 64 KB.
- **TLS** is checked with one handshake on port 443 with a timeout of 10 seconds; it does not
  list every cipher or protocol version the server supports.
- **SPF** is checked for presence, count and its `all` ending; `include:` chains and the
  DNS lookup limit are not evaluated, and a record that ends with `redirect=` is shown as
  having no `all`.
- **DMARC** for subdomains walks up to four parent names, never to the top-level domain.
- Only public addresses are contacted; up to 5,000 entries per run.

### FAQ

**Is it legal to use?** The audit only reads what every browser and mail server sees: public
headers, the certificate and public DNS records. It sends no attacks and probes no paths.
Audit only domains you own or may check, and see the fair use rules at the end of this page.

**Does it respect robots.txt?** Yes. If `robots.txt` disallows the home page, the headers are
not read and the result says so.

**Does it store personal data?** No. It returns flags, dates and counts. It never returns
cookie names or values, the e-mail addresses from DMARC records (it only says whether reports
are requested), `security.txt` contacts or the CAA `iodef` contact.

**How fast is it?** Domains are audited in groups of 20 at a time, with at most 10 web requests
in flight and a polite pause between requests to the same host. The duration depends on how
fast the servers answer.

**Can I schedule it?** Yes, with a schedule in Apify Console, for example daily for
certificate monitoring or monthly for a portfolio review.

**Can I use it from Python, JavaScript or the API?** Yes, see Integrations below.

**Can AI agents use it?** Yes, through Apify's MCP server, for example to answer "what is the
security grade of these domains and what should we fix first?".

**Why was a domain not charged?** Entries that are not valid, do not resolve or point to a
non-public address are free, as are entries that failed with an internal error.

**Why is the grade empty?** The site's `robots.txt` does not allow automated clients on the
home page, or answered with a server error. The e-mail checks are still in the result.

**How is it different from a one-domain-at-a-time online header checker?** It audits
thousands of domains in one run, covers headers, TLS, `security.txt` and e-mail DNS together,
gives one consistent grade and returns structured data for spreadsheets, dashboards and
automations.

**What happens on errors and timeouts?** A failed request becomes a finding (for example
"HTTPS does not work (timeout)") and the run goes on with the next domain. Results written
before a run timeout stay in the dataset.

### Integrations

The actor ID is `HelveticLabs/security-audit`.

**Python** (`pip install apify-client`):

```python
from decimal import Decimal

from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("HelveticLabs/security-audit").call(
    run_input={"domains": ["example.com", "example.org"], "checkEmailDns": True},
    max_total_charge_usd=Decimal("1"),  # optional spending limit for this run
)
## apify-client 3.x; with older versions use run["defaultDatasetId"]
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item["domain"], item.get("grade"), item.get("email_score"))
```

**JavaScript** (`npm install apify-client`):

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('HelveticLabs/security-audit').call(
    { domains: ['example.com', 'example.org'], checkEmailDns: true },
    { maxTotalChargeUsd: 1 },
);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) console.log(item.domain, item.grade, item.tls?.days_left);
```

**HTTP API:** `POST https://api.apify.com/v2/acts/HelveticLabs~security-audit/runs` with the
input as the JSON body; add `maxTotalChargeUsd` as a query parameter to cap the cost.

**No-code and automation:** connect the Actor to Make, Zapier or n8n, or add a webhook that
fires when a run finishes, for example to open a ticket when a grade drops or a certificate
has fewer than 30 days left.

**AI agents (MCP):** Apify's MCP server lets AI agents and MCP clients run this Actor as a tool;
pass `maxTotalChargeUsd` in the call options to cap the spend.

### Related HelveticLabs actors

| Actor | What it does |
| --- | --- |
| [URL Status & Redirect Checker](https://apify.com/HelveticLabs/url-status-checker) | Status code, redirect chain, final URL and response time for up to 100,000 URLs. |
| [Website Health Audit: Broken Links & SEO Checker](https://apify.com/HelveticLabs/website-health-audit) | Crawls a site for broken links, redirects and on-page SEO issues. |
| [Sitemap URL Extractor & Validator](https://apify.com/HelveticLabs/sitemap-extractor) | Every URL from a site's sitemaps, with lastmod dates. |
| [AI Crawler Access Checker](https://apify.com/HelveticLabs/ai-crawler-checker) | Which AI bots a site's robots.txt allows, plus llms.txt. |

### Support and feedback

Questions, wrong results or ideas for further checks? Open an issue in the **Issues** tab on
this Actor's page, or write to <contact@helveticlabs.org>.
Include the run ID if a run is involved.

### Provider, privacy and fair use

**Provider:** HelveticLabs, sole proprietorship of Marvin Krieg, c/o SwissMailBox 170,
12 Rue Le Corbusier, 1208 Genève, Switzerland. E-mail: contact@helveticlabs.org.
Imprint: https://www.helveticlabs.org/imprint

**Privacy:** This Actor runs on the Apify platform, in your Apify account. It processes only
the URLs or domains you enter and the public technical data the checked servers return
(status codes, headers, certificates, DNS records, sitemap URLs, links). It does not collect
personal data: it never stores or returns page text (where a page's HTML is read, it is read
in memory only, to find links and measure tags), and it leaves out e-mail addresses, cookie
names and values and similar values. Your input and results stay in your Apify account and are
stored by Apify under its own terms (https://apify.com/privacy-policy). The provider sees
only the usage statistics Apify shows to Actor authors (such as the number of users and
runs), not your input or results, unless you share a run for support. Questions about
privacy: contact@helveticlabs.org.

**Fair use:** Check only sites you own or may check. Do not use the results to attack
systems or people. The Actor respects robots.txt, identifies itself, and keeps a polite
pace per site.

**No warranty:** The results are automated checks and can be incomplete. They are not a
penetration test, legal advice or a compliance certificate.

# Actor input Schema

## `domains` (type: `array`):

Domains (example.com) or URLs (https://www.example.com/page). The home page of each host is audited.

## `checkEmailDns` (type: `boolean`):

Also check whether the domain is protected against e-mail spoofing.

## `timeoutSecs` (type: `integer`):

How long to wait for each response.

## Actor input object example

```json
{
  "domains": [
    "example.com"
  ],
  "checkEmailDns": true,
  "timeoutSecs": 15
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "domains": [
        "example.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("helveticlabs/security-audit").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "domains": ["example.com"] }

# Run the Actor and wait for it to finish
run = client.actor("helveticlabs/security-audit").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "domains": [
    "example.com"
  ]
}' |
apify call helveticlabs/security-audit --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,helveticlabs/security-audit"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/OAkcImxprsV3cxRzJ/builds/gvdCaESxfw5JIq1YT/openapi.json
