# Aback Audit: every check > 55 checks in 7 categories. ## Crawlability ### The audited URL answers with HTTP 200 - **Id:** `crawl.http-status` - **Severity:** critical - **Confidence:** high - **Checks:** The URL ends in HTTP 200 after redirects. - **Why it matters:** A page that does not answer with 200 cannot be indexed. Every other check on this page is irrelevant if the crawler never receives the document. - **How to fix:** Fix the server response for this URL. If the page moved, update the links that point at it instead of relying on a redirect chain. - **Documentation:** https://abackaudit.com/checks/http-status ### Redirects are short and do not loop - **Id:** `crawl.redirect-chain` - **Severity:** medium - **Confidence:** high - **Checks:** At most one redirect hop, and no redirect loops. - **Why it matters:** Every hop adds latency for the crawler and for the visitor, and long chains dilute link signals. Loops make a page unreachable. - **How to fix:** Point links directly at the final URL. Keep one redirect at most, from the old address to the canonical one. - **Documentation:** https://abackaudit.com/checks/redirect-chain ### The site is served over HTTPS - **Id:** `crawl.https` - **Severity:** high - **Confidence:** high - **Checks:** The final URL uses HTTPS and the http version redirects to it. - **Why it matters:** HTTPS is a confirmed ranking signal and browsers flag insecure pages. An http page that does not redirect leaves two addresses for the same content. - **How to fix:** Serve the whole site over HTTPS and redirect every http request to the https version with a 301. - **Documentation:** https://abackaudit.com/checks/https ### One canonical host answers for every variant - **Id:** `crawl.host-canonical` - **Severity:** medium - **Confidence:** high - **Checks:** The www and non-www variants, with and without a trailing slash, resolve to a single form. - **Why it matters:** When several addresses serve the same content, search engines have to guess which one to index and which one to keep in results. - **How to fix:** Pick one host and one trailing slash style, then redirect every other variant to it with a 301. - **Documentation:** https://abackaudit.com/checks/host-canonical ### robots.txt exists and is usable - **Id:** `crawl.robots-txt` - **Severity:** high - **Confidence:** high - **Checks:** The file exists, returns 200, parses, and stays under 500 KiB. - **Why it matters:** robots.txt is how a site tells crawlers where to go. A missing or broken file removes that control and hides real crawl problems. - **How to fix:** Publish a plain text robots.txt at the root of the site and keep it small. Test it with the robots testing tool before deploying. - **Documentation:** https://abackaudit.com/checks/robots-txt ### The default robots rules do not block the site - **Id:** `crawl.robots-blocking` - **Severity:** critical - **Confidence:** high - **Checks:** The wildcard rules in robots.txt do not block the audited URL or the key paths of the site. - **Why it matters:** A blanket Disallow in the wildcard group hides the whole site from every crawler that does not name itself in robots.txt. This is the single most common reason a site cannot be indexed. - **How to fix:** Remove the blocking rule, or scope it to the paths that really should be private. Test the file against the audited URL before publishing it. - **Documentation:** https://abackaudit.com/checks/robots-blocking ### A valid sitemap is published and declared - **Id:** `crawl.sitemap` - **Severity:** high - **Confidence:** high - **Checks:** The sitemap exists, parses as XML, is declared in robots.txt, and its sample urls answer with 200. - **Why it matters:** A sitemap is the clearest list of pages a site wants indexed. It speeds up discovery and makes coverage visible. - **How to fix:** Generate a sitemap with the urls that should be indexed, publish it at /sitemap.xml and add a Sitemap line to robots.txt. - **Documentation:** https://abackaudit.com/checks/sitemap ### The page is not marked as noindex - **Id:** `crawl.noindex` - **Severity:** critical - **Confidence:** high - **Checks:** No noindex directive appears in the meta robots tag or in the X-Robots-Tag header. - **Why it matters:** noindex is a direct instruction to keep the page out of search results. It is often left behind by a staging deployment. - **How to fix:** Remove the noindex directive from the meta robots tag and from the X-Robots-Tag header. Check the deployment configuration as well, not only the template. - **Documentation:** https://abackaudit.com/checks/noindex ### The canonical link points at the page itself - **Id:** `crawl.canonical` - **Severity:** high - **Confidence:** high - **Checks:** A rel=canonical link exists, is absolute, matches the page and does not point at a redirect or an error. - **Why it matters:** The canonical link tells search engines which address is the real one. A wrong canonical can move the ranking of a page to another address. - **How to fix:** Set the canonical link to the absolute, final URL of the page, one per page, and make sure it does not point at a redirecting or error address. - **Documentation:** https://abackaudit.com/checks/canonical ### Internal links resolve - **Id:** `crawl.internal-links` - **Severity:** medium - **Confidence:** high - **Checks:** Sampled internal links answer with 2xx, or with a single redirect. - **Why it matters:** Broken internal links waste crawl budget and strand visitors. They are also a strong signal that the site is not maintained. - **How to fix:** Fix or remove the broken links. Templates that build urls from ids should be checked first, they fail the most often. - **Documentation:** https://abackaudit.com/checks/internal-links ## AI search readiness ### AI crawlers are allowed in robots.txt - **Id:** `ai.crawler-access` - **Severity:** medium - **Confidence:** high - **Checks:** What robots.txt says about each known AI crawler, classified as training, search or user triggered. - **Why it matters:** Robots.txt is the only place a site states its policy towards AI crawlers. Blocking an AI search crawler removes the site from that assistant, blocking a training crawler is a legitimate choice. - **How to fix:** Decide per crawler class. Allowing training crawlers while blocking search crawlers is a valid combination, just make it explicit in robots.txt. - **Documentation:** https://abackaudit.com/checks/crawler-access ### AI crawlers receive the same page as everyone else - **Id:** `ai.bot-fetch-parity` - **Severity:** high - **Confidence:** high - **Checks:** The page returns the same status and substantially the same content to AI crawler user agents as to a default client. - **Why it matters:** Firewalls, bot management and CDN rules often block AI crawlers before robots.txt is even read. The site then looks open to humans and invisible to assistants. - **How to fix:** Review the WAF, CDN and rate limiting rules that match the AI crawler user agents and allow them through. - **Documentation:** https://abackaudit.com/checks/bot-fetch-parity ### An llms.txt file describes the site - **Id:** `ai.llms-txt` - **Severity:** low - **Confidence:** medium - **Checks:** The file exists, is plain text or Markdown, has a title and a summary, and its links resolve. - **Why it matters:** llms.txt is an emerging convention for giving language models a curated map of a site. It is not used by any major crawler yet, so treat it as preparation rather than as a ranking factor. - **How to fix:** Publish a plain text llms.txt at the root of the site with an H1 title, a short summary and links to the pages that matter. - **Documentation:** https://abackaudit.com/checks/llms-txt ### An llms-full.txt file is available - **Id:** `ai.llms-full-txt` - **Severity:** info - **Confidence:** medium - **Checks:** The optional llms-full.txt file exists. - **Why it matters:** The full variant carries the complete text of the documentation of a site. It is entirely optional and never affects a score. - **How to fix:** Add llms-full.txt next to llms.txt if the site has long form documentation worth exposing to models. - **Documentation:** https://abackaudit.com/checks/llms-full-txt ### The main content is in the initial HTML - **Id:** `ai.content-without-js` - **Severity:** high - **Confidence:** high - **Checks:** The main content is present before JavaScript runs, not only after the page is rendered. - **Why it matters:** Most AI crawlers read the HTML they receive and do not execute JavaScript. Content that only exists after rendering is invisible to them. - **How to fix:** Render the main content on the server. Client side rendering should enhance the page, not create it. - **Documentation:** https://abackaudit.com/checks/content-without-js ### A Markdown version of the page is offered - **Id:** `ai.markdown-alternate` - **Severity:** info - **Confidence:** medium - **Checks:** The page offers a Markdown version through an alternate link or a .md URL. - **Why it matters:** Markdown is cheaper for a model to read than HTML. Offering it is a small, well received signal for AI tools. - **How to fix:** Add a link rel=alternate type=text/markdown element that points at the Markdown version of the page. - **Documentation:** https://abackaudit.com/checks/markdown-alternate ### Agent discovery files are published - **Id:** `ai.agent-discovery` - **Severity:** info - **Confidence:** medium - **Checks:** Machine readable discovery files such as an MCP server card, an API catalog and an OpenAPI document are available. - **Why it matters:** Discovery files tell agents what a site exposes to machines. They are optional, but they remove guesswork for any integration. - **How to fix:** Publish an OpenAPI document and, if the site exposes an MCP server, a server card under /.well-known/. - **Documentation:** https://abackaudit.com/checks/agent-discovery ## On-page SEO ### The title tag is present and well sized - **Id:** `page.title` - **Severity:** high - **Confidence:** high - **Checks:** A title exists, is roughly 30 to 60 characters, and is unique across the sampled pages. - **Why it matters:** The title is the strongest on-page signal and the headline of every search result. Missing or duplicated titles make pages compete with each other. - **How to fix:** Give every page a title that names the page, uses about 30 to 60 characters, and differs from every other page on the site. - **Documentation:** https://abackaudit.com/checks/title ### The meta description is present and well sized - **Id:** `page.meta-description` - **Severity:** medium - **Confidence:** high - **Checks:** A meta description exists, is roughly 70 to 160 characters, and is unique across the sampled pages. - **Why it matters:** The description is the snippet under the title. It decides whether someone clicks, and duplicated descriptions waste the space. - **How to fix:** Write one description per page, around 70 to 160 characters, that states what the page offers. - **Documentation:** https://abackaudit.com/checks/meta-description ### The page has exactly one H1 - **Id:** `page.h1` - **Severity:** medium - **Confidence:** high - **Checks:** Exactly one non-empty H1 element exists. - **Why it matters:** The H1 tells both readers and crawlers what the page is about. Several H1s make the hierarchy ambiguous, and an empty one carries no information. - **How to fix:** Keep one H1 that names the topic of the page, and use H2 and H3 for the structure below it. - **Documentation:** https://abackaudit.com/checks/h1 ### The heading outline does not skip levels - **Id:** `page.heading-order` - **Severity:** low - **Confidence:** high - **Checks:** Headings descend one level at a time and none of them is empty. - **Why it matters:** A clean outline is how a screen reader user navigates a page. Skipped levels break that navigation and hide the structure from crawlers. - **How to fix:** Move a heading up or down one level so that the sequence never jumps from H2 to H4. - **Documentation:** https://abackaudit.com/checks/heading-order ### The document declares its language - **Id:** `page.lang` - **Severity:** low - **Confidence:** high - **Checks:** The html element carries a valid BCP 47 language tag. - **Why it matters:** The language tag lets search engines target the right locale and lets screen readers pick the right voice. - **How to fix:** Add a lang attribute to the html element, for example lang="en" or lang="de". - **Documentation:** https://abackaudit.com/checks/lang ### The hreflang annotations are complete - **Id:** `page.hreflang` - **Severity:** medium - **Confidence:** high - **Checks:** When hreflang is used, the codes are valid, the links are reciprocal and an x-default exists. - **Why it matters:** hreflang tells search engines which language version to show. One sided annotations are ignored, which is worse than not using them at all. - **How to fix:** List every language version on every version of the page, include an x-default entry, and make sure the links point at each other. - **Documentation:** https://abackaudit.com/checks/hreflang ### The Open Graph tags are complete - **Id:** `page.open-graph` - **Severity:** low - **Confidence:** high - **Checks:** og:title, og:description, og:image and og:url are present and the image resolves. - **Why it matters:** Open Graph tags control the preview a post gets when it is shared on social networks and in chat applications. Missing tags produce a bare link. - **How to fix:** Add the four Open Graph tags to the page head and point og:image at an absolute, publicly reachable image. - **Documentation:** https://abackaudit.com/checks/open-graph ### The Twitter card tags are complete - **Id:** `page.twitter-card` - **Severity:** low - **Confidence:** high - **Checks:** twitter:card is set and the fields that match the card type are present. - **Why it matters:** Without a card type, X shows a plain link. With it, the shared preview carries the title, the description and the image. - **How to fix:** Set twitter:card to summary or summary_large_image and add twitter:title, twitter:description and twitter:image. - **Documentation:** https://abackaudit.com/checks/twitter-card ### Images carry alternative text - **Id:** `page.image-alt` - **Severity:** medium - **Confidence:** high - **Checks:** Every image that carries meaning has an alt attribute. - **Why it matters:** Alternative text is the only description a screen reader user gets of an image, and it is also how image search understands the picture. - **How to fix:** Describe the content of every meaningful image in its alt attribute. Use alt="" for purely decorative images. - **Documentation:** https://abackaudit.com/checks/image-alt ### The viewport allows zooming - **Id:** `page.viewport` - **Severity:** high - **Confidence:** high - **Checks:** A viewport meta tag is present and does not disable zoom. - **Why it matters:** Blocking zoom makes the page unusable for people who need to magnify it, and it is a well known accessibility failure. - **How to fix:** Use a viewport tag such as width=device-width, initial-scale=1 and leave user-scalable out, or set it to a value above 1. - **Documentation:** https://abackaudit.com/checks/viewport ### The page carries enough content - **Id:** `page.thin-content` - **Severity:** low - **Confidence:** low - **Checks:** The visible word count is not very low for the page type. - **Why it matters:** Pages with almost no text rarely satisfy a search intent. This check is a heuristic, so treat the number as a prompt to look rather than as a verdict. - **How to fix:** Make sure the page answers the question it is about. If the content lives in an image, in a video or in a script, it is invisible to a crawler. - **Documentation:** https://abackaudit.com/checks/thin-content ## Structured data ### The JSON-LD blocks are valid - **Id:** `schema.json-ld-valid` - **Severity:** high - **Confidence:** high - **Checks:** Every JSON-LD block parses as JSON and declares a context and a type. - **Why it matters:** A block with a syntax error is ignored completely. A block without a context or a type is read but cannot be matched to anything. - **How to fix:** Validate the JSON before it ships. A block must contain @context set to https://schema.org and at least one @type. - **Documentation:** https://abackaudit.com/checks/json-ld-valid ### The structured data types found on the page - **Id:** `schema.types-detected` - **Severity:** info - **Confidence:** high - **Checks:** Lists the schema.org types the page declares. - **Why it matters:** The list makes it easy to see what a crawler can understand about the page. It never affects the score. - **How to fix:** Use the type that matches the page. Article for posts, Product for products, LocalBusiness for a business page. - **Documentation:** https://abackaudit.com/checks/types-detected ### The structured data carries its required properties - **Id:** `schema.required-properties` - **Severity:** medium - **Confidence:** high - **Checks:** Detected types include the required and recommended properties for that type. - **Why it matters:** A rich result is only granted when the required properties are present. Missing them leaves the markup unused. - **How to fix:** Add the missing properties to the JSON-LD block. The check lists exactly which ones are absent. - **Documentation:** https://abackaudit.com/checks/required-properties ### The site identifies its organisation - **Id:** `schema.organization` - **Severity:** medium - **Confidence:** high - **Checks:** An Organization or WebSite entity is present. An Organization also declares a logo and its sameAs profiles. - **Why it matters:** The organisation entity is what connects the pages of a site to the brand behind them, in search results and in knowledge panels. - **How to fix:** Add an Organization entity with name, url, logo and the sameAs profiles of the brand. - **Documentation:** https://abackaudit.com/checks/organization ### The page declares its breadcrumbs - **Id:** `schema.breadcrumbs` - **Severity:** low - **Confidence:** high - **Checks:** A BreadcrumbList entity is present on nested pages. - **Why it matters:** Breadcrumbs replace the raw URL in the search result with a readable path, and they describe the structure of the site. - **How to fix:** Add a BreadcrumbList entity with one ListItem per level, pointing at the real address of that level. - **Documentation:** https://abackaudit.com/checks/breadcrumbs ## Performance ### The server answers quickly - **Id:** `perf.ttfb` - **Severity:** medium - **Confidence:** medium - **Checks:** Time to first byte, measured from the audit location. - **Why it matters:** Every request starts with this delay. A slow server makes every other performance number worse and is visible to the visitor before anything is drawn. - **How to fix:** Cache the response at the edge, keep the origin close to the visitor, and make sure the server does not do slow work before it answers. - **Documentation:** https://abackaudit.com/checks/ttfb ### The largest element appears quickly - **Id:** `perf.lcp` - **Severity:** high - **Confidence:** medium - **Checks:** Largest Contentful Paint on a throttled mobile profile. - **Why it matters:** Largest Contentful Paint is what a visitor perceives as the loading of the page. It is one of the Core Web Vitals and it correlates with how long people stay. - **How to fix:** Serve the largest element early. Preload the hero image, avoid lazy loading it, and keep the server response fast. - **Documentation:** https://abackaudit.com/checks/lcp ### The page does not shift while it loads - **Id:** `perf.cls` - **Severity:** medium - **Confidence:** medium - **Checks:** Cumulative Layout Shift on a throttled mobile profile. - **Why it matters:** Content that jumps after it appears is the most common complaint about a slow feeling website. A stable layout reads as a faster one. - **How to fix:** Reserve the space for images, ads and embeds with explicit width and height, and avoid inserting content above what is already on screen. - **Documentation:** https://abackaudit.com/checks/cls ### The page responds to input quickly - **Id:** `perf.tbt` - **Severity:** medium - **Confidence:** medium - **Checks:** Total Blocking Time, the lab stand in for Interaction to Next Paint. - **Why it matters:** A page that blocks the main thread feels frozen. Long tasks are usually caused by heavy scripts running during load. - **How to fix:** Split long tasks, defer scripts that are not needed for the first view, and reduce the amount of JavaScript the page ships. - **Documentation:** https://abackaudit.com/checks/tbt ### The page is not too heavy - **Id:** `perf.page-weight` - **Severity:** low - **Confidence:** medium - **Checks:** Total transfer size of the page and its subresources. - **Why it matters:** Every kilobyte costs bandwidth and battery. On a slow connection a heavy page is the difference between a visit and a bounce. - **How to fix:** Serve smaller images, remove unused scripts and stylesheets, and prefer modern formats such as AVIF and WebP. - **Documentation:** https://abackaudit.com/checks/page-weight ### Text assets are compressed - **Id:** `perf.compression` - **Severity:** medium - **Confidence:** high - **Checks:** Text responses are served with gzip or Brotli. - **Why it matters:** Compression cuts the bytes on the wire by roughly three quarters for HTML, CSS and JavaScript. It is the cheapest speed win there is. - **How to fix:** Enable Brotli or gzip compression for text responses at the CDN or the origin. - **Documentation:** https://abackaudit.com/checks/compression ### Static assets are cached - **Id:** `perf.caching` - **Severity:** low - **Confidence:** medium - **Checks:** Static assets carry an effective Cache-Control header. - **Why it matters:** A visitor who comes back should not download the same files again. Long lived cache headers turn repeat visits into a near instant page. - **How to fix:** Give fingerprinted assets a long max-age, for example one year, and revalidate HTML with a short max-age or ETag. - **Documentation:** https://abackaudit.com/checks/caching ### Images use modern formats - **Id:** `perf.image-formats` - **Severity:** low - **Confidence:** medium - **Checks:** Images are served in modern formats and are not grossly oversized. - **Why it matters:** Images dominate the weight of a typical page. AVIF and WebP cut the size of a photograph by half compared with JPEG, at the same quality. - **How to fix:** Serve AVIF or WebP with a fallback, resize images to the size they are displayed at, and compress them. - **Documentation:** https://abackaudit.com/checks/image-formats ### The page is not blocked by head resources - **Id:** `perf.render-blocking` - **Severity:** medium - **Confidence:** medium - **Checks:** Render blocking CSS and JavaScript in the document head. - **Why it matters:** The browser cannot paint anything until it has read the blocking resources in the head. Every one of them delays the first pixel. - **How to fix:** Inline the small amount of critical CSS, load the rest asynchronously, and defer scripts that are not needed for the first view. - **Documentation:** https://abackaudit.com/checks/render-blocking ## Accessibility ### Text meets the colour contrast requirement - **Id:** `a11y.contrast` - **Severity:** medium - **Confidence:** medium - **Checks:** Text contrast follows WCAG 2 AA for normal and large text. - **Why it matters:** Low contrast text is unreadable for a large share of people, especially on a phone in daylight. It is the most common accessibility failure on the web. - **How to fix:** Darken the text or lighten the background until the pair reaches 4.5 to 1 for normal text and 3 to 1 for large text. - **Documentation:** https://abackaudit.com/checks/contrast ### Form controls have labels - **Id:** `a11y.form-labels` - **Severity:** high - **Confidence:** high - **Checks:** Every form control carries an accessible label. - **Why it matters:** A screen reader announces an unlabelled field as an empty edit box. People cannot tell what belongs in it. - **How to fix:** Give every field a label element linked with the for attribute, or an aria-label or aria-labelledby attribute. - **Documentation:** https://abackaudit.com/checks/form-labels ### The page uses landmarks - **Id:** `a11y.landmarks` - **Severity:** low - **Confidence:** high - **Checks:** The page has a main landmark and a sensible landmark structure. - **Why it matters:** Landmarks let assistive technology jump between the header, the navigation and the content, instead of reading the page from the top. - **How to fix:** Wrap the main content in a main element and use header, nav, aside and footer where they apply. - **Documentation:** https://abackaudit.com/checks/landmarks ### Interactive elements have accessible names - **Id:** `a11y.names` - **Severity:** high - **Confidence:** high - **Checks:** Links, buttons and images expose a name to assistive technology. - **Why it matters:** A link that says only click here is unusable with a screen reader. The name is what a person hears and what they search for. - **How to fix:** Give every link and button text that describes the destination, and give every meaningful image an alt attribute. - **Documentation:** https://abackaudit.com/checks/names ### The ARIA usage is valid - **Id:** `a11y.aria` - **Severity:** medium - **Confidence:** medium - **Checks:** ARIA roles and attributes are used in ways that assistive technology can act on. - **Why it matters:** Wrong ARIA is worse than no ARIA. A role that contradicts the element, or a reference to an id that does not exist, hides content instead of exposing it. - **How to fix:** Remove ARIA that duplicates native semantics, point aria references at ids that exist, and use roles that match the element. - **Documentation:** https://abackaudit.com/checks/aria ## Security headers ### The certificate is valid for the host - **Id:** `sec.tls-certificate` - **Severity:** high - **Confidence:** medium - **Checks:** The TLS handshake succeeds, so the chain is trusted and the hostname matches. - **Why it matters:** A browser that cannot verify the certificate shows a full page warning, and every link on the site becomes a risk to click. - **How to fix:** Serve the site with a certificate that covers the hostname and chains to a trusted root. Renew it before it expires. - **Documentation:** https://abackaudit.com/checks/tls-certificate ### Strict Transport Security is set - **Id:** `sec.hsts` - **Severity:** medium - **Confidence:** high - **Checks:** The Strict-Transport-Security header is present with a max-age of at least six months. - **Why it matters:** HSTS tells browsers to use HTTPS for the site from the first visit, which removes the window where an attacker can downgrade the connection. - **How to fix:** Send Strict-Transport-Security: max-age=31536000; includeSubDomains once HTTPS works everywhere on the domain. - **Documentation:** https://abackaudit.com/checks/hsts ### The page has no mixed content - **Id:** `sec.mixed-content` - **Severity:** high - **Confidence:** high - **Checks:** No http subresource is loaded by an https page. - **Why it matters:** Browsers block active mixed content and warn about passive mixed content. An attacker on the network can tamper with anything loaded over http. - **How to fix:** Change every http reference to https, including images, stylesheets, scripts and iframes. - **Documentation:** https://abackaudit.com/checks/mixed-content ### A Content Security Policy is set - **Id:** `sec.csp` - **Severity:** low - **Confidence:** high - **Checks:** A Content-Security-Policy header exists, and script-src does not rely on unsafe-inline. - **Why it matters:** A content security policy is the strongest defence against cross site scripting. It limits what an injected script is allowed to do. - **How to fix:** Start with a report only policy, then tighten it. Hashes or nonces remove the need for unsafe-inline. - **Documentation:** https://abackaudit.com/checks/csp ### The content type is not sniffed - **Id:** `sec.content-type-options` - **Severity:** low - **Confidence:** high - **Checks:** The X-Content-Type-Options header is set to nosniff. - **Why it matters:** Without nosniff a browser may interpret a file as a different type than the one the server declared, which turns an upload into an attack. - **How to fix:** Send X-Content-Type-Options: nosniff on every response. - **Documentation:** https://abackaudit.com/checks/content-type-options ### A referrer policy is set - **Id:** `sec.referrer-policy` - **Severity:** low - **Confidence:** high - **Checks:** The Referrer-Policy header is present. - **Why it matters:** The referrer policy decides how much of the current URL travels with a request to another site. A strict policy keeps internal paths private. - **How to fix:** Send Referrer-Policy: strict-origin-when-cross-origin, or stricter. - **Documentation:** https://abackaudit.com/checks/referrer-policy ### The page cannot be framed - **Id:** `sec.clickjacking` - **Severity:** low - **Confidence:** high - **Checks:** X-Frame-Options is set, or the content security policy declares frame-ancestors. - **Why it matters:** A page that can be framed can be covered by a convincing overlay in another site, which is how clickjacking attacks work. - **How to fix:** Send X-Frame-Options: DENY, or add frame-ancestors to the content security policy. - **Documentation:** https://abackaudit.com/checks/clickjacking ### Cookies are set with safe flags - **Id:** `sec.cookie-flags` - **Severity:** low - **Confidence:** high - **Checks:** Cookies set by the response use Secure, HttpOnly where appropriate, and SameSite. - **Why it matters:** A cookie without Secure travels over plain http, one without HttpOnly is readable by scripts, and one without SameSite is sent with cross site requests. - **How to fix:** Set Secure, HttpOnly and SameSite=Lax or Strict on every cookie that needs it. - **Documentation:** https://abackaudit.com/checks/cookie-flags