Each Monday, checks the sites you list for the browser protections they should switch on, and emails what is missing and how to fix it.

UsesGmailOpenAI

Check your websites' security settings every week

ScheduleRun every Monday at 08:00.Run every Monday at 08:00.
ValuesSet siteList to blank.Set siteList to blank.
ValuesSet reportEmail to blank.Set reportEmail to blank.
TextSplit siteList with replaced by "Split siteList with replaced by with , replaced by by a new line and save it as siteEntries.
ValuesSet siteReports to an empty list.Set siteReports to an empty list.
ValuesSet unreachable to an empty list.Set unreachable to an empty list.
ValuesSet sitesWithGaps to 0.Set sitesWithGaps to 0.
Decisions & LoopsFor each siteEntry in siteEntries:For each siteEntry in siteEntries:
TextTrim siteEntry and save it as entry.Trim siteEntry and save it as entry.
Decisions & LoopsIf entry is emptyIf entry is empty
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
TextReplace http:// with in entry with https:// replaced by (ignoring case) (ignoring case) and save it as siteHost.Replace http:// with in entry with https:// replaced by (ignoring case) (ignoring case) and save it as siteHost.
Decisions & LoopsIf siteHost is emptyIf siteHost is empty
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
ValuesSet checkUrl to http://@siteHost.Set checkUrl to http://@siteHost.
ValuesSet reached to false.Set reached to false.
ValuesSet finalUrl to blank.Set finalUrl to blank.
ValuesSet responseStatus to 0.Set responseStatus to 0.
ValuesSet responseHeaders to an empty record.Set responseHeaders to an empty record.
Decisions & LoopsIf a step below fails, save the error as fetchErrorIf a step below fails, save the error as fetchError
Try
HTTPFetch checkUrl and save it as response.Fetch checkUrl and save it as response.
TextTrim response.url and save it as finalUrl.Trim response.url and save it as finalUrl.
ValuesChange responseStatus to response.status.Change responseStatus to response.status.
ValuesChange responseHeaders to response.headers.Change responseHeaders to response.headers.
ValuesChange reached to true.Change reached to true.
On error
TextReplace checkUrl with the site address in fetchError.message and save it as safeReason.Replace checkUrl with the site address in fetchError.message and save it as safeReason.
ListsAdd siteHost - could not be reached: safeReason to the end of unreachable and save it as unreachable.Add siteHost - could not be reached: safeReason to the end of unreachable and save it as unreachable.
Decisions & LoopsIf reached isn't yesIf reached isn't yes
Yes
Decisions & LoopsSkip to the next item.Skip to the next item.
No
No steps
ValuesSet missingHeaders to an empty list.Set missingHeaders to an empty list.
Decisions & LoopsIf responseHeaders["strict-transport-security"] is emptyIf responseHeaders["strict-transport-security"] is empty
Yes
ListsAdd Strict-Transport-Security to the end of missingHeaders and save it as missingHeaders.Add Strict-Transport-Security to the end of missingHeaders and save it as missingHeaders.
No
No steps
Decisions & LoopsIf responseHeaders["content-security-policy"] is emptyIf responseHeaders["content-security-policy"] is empty
Yes
ListsAdd Content-Security-Policy to the end of missingHeaders and save it as missingHeaders.Add Content-Security-Policy to the end of missingHeaders and save it as missingHeaders.
No
No steps
Decisions & LoopsIf responseHeaders["x-frame-options"] is emptyIf responseHeaders["x-frame-options"] is empty
Yes
ListsAdd X-Frame-Options to the end of missingHeaders and save it as missingHeaders.Add X-Frame-Options to the end of missingHeaders and save it as missingHeaders.
No
No steps
Decisions & LoopsIf responseHeaders["x-content-type-options"] is emptyIf responseHeaders["x-content-type-options"] is empty
Yes
ListsAdd X-Content-Type-Options to the end of missingHeaders and save it as missingHeaders.Add X-Content-Type-Options to the end of missingHeaders and save it as missingHeaders.
No
No steps
Decisions & LoopsIf responseHeaders["referrer-policy"] is emptyIf responseHeaders["referrer-policy"] is empty
Yes
ListsAdd Referrer-Policy to the end of missingHeaders and save it as missingHeaders.Add Referrer-Policy to the end of missingHeaders and save it as missingHeaders.
No
No steps
TextCheck whether finalUrl starts with https:// (ignoring case) and save it as redirectsToHttps.Check whether finalUrl starts with https:// (ignoring case) and save it as redirectsToHttps.
ValuesSet httpsLine to HTTPS: the plain http address is sent on to finalUrl.Set httpsLine to HTTPS: the plain http address is sent on to finalUrl.
Decisions & LoopsIf redirectsToHttps isn't yesIf redirectsToHttps isn't yes
Yes
ValuesChange httpsLine to HTTPS: the plain http address was NOT sent on to https - it ended at finalUrl.Change httpsLine to HTTPS: the plain http address was NOT sent on to https - it ended at finalUrl.
No
No steps
ValuesSet headerLine to Security headers: all five present.Set headerLine to Security headers: all five present.
Decisions & LoopsIf missingHeaders isn't emptyIf missingHeaders isn't empty
Yes
ValuesChange headerLine to Missing security headers: missingHeaders joined by , .Change headerLine to Missing security headers: missingHeaders joined by , .
No
No steps
ValuesSet serverBanner to responseHeaders.server.Set serverBanner to responseHeaders.server.
ValuesSet serverLine to Server header: not sent.Set serverLine to Server header: not sent.
Decisions & LoopsIf serverBanner isn't emptyIf serverBanner isn't empty
Yes
ValuesChange serverLine to Server header: serverBanner.Change serverLine to Server header: serverBanner.
No
No steps
Decisions & LoopsIf missingHeaders isn't empty or redirectsToHttps isn't yesIf missingHeaders isn't empty or redirectsToHttps isn't yes
Yes
ValuesAdd 1 to sitesWithGaps.Add 1 to sitesWithGaps.
No
No steps
ListsAdd siteHost (read at finalUrl, status responseStatus)Add siteHost (read at finalUrl, status responseStatus) httpsLine headerLine serverLine to the end of siteReports and save it as siteReports.
Decisions & LoopsIf siteReports is empty and unreachable is emptyIf siteReports is empty and unreachable is empty
Yes
Decisions & LoopsStop and report a problem: None of the lines in the 'siteList' step held a website address. Put one address per line, for example acme.com, then run it again.Stop and report a problem: None of the lines in the 'siteList' step held a website address. Put one address per line, for example acme.com, then run it again.
No
No steps
TextJoin siteReports with a blank line and save it as findings.Join siteReports with a blank line and save it as findings.
Decisions & LoopsIf unreachable isn't emptyIf unreachable isn't empty
Yes
ValuesChange findings to findingsChange findings to findings Could not be checked: unreachable joined by a new line.
No
No steps
ValuesSet explanationText to blank.Set explanationText to blank.
Decisions & LoopsIf a step below fails, save the error as explainErrorIf a step below fails, save the error as explainError
Try
OpenAIOpenAIAsk OpenAI: 'You are writing the plain-English part of a weekly security-header summary for the small team that owns the websites below.Ask OpenAI: 'You are writing the plain-English part of a weekly security-header summary for the small team that owns the websites below. Only the response headers of one ordinary page request per site were read - the same headers any visitor's browser receives. Nothing was scanned, probed or tested, and no address other than the ones listed was contacted. For each site with something missing, write two or three sentences: what that header does, what an ordinary visitor is left open to without it, and the concrete change to make in the web server or CDN configuration. Where a Server header names a version number, note that hiding the version is a one-line configuration change. Do not judge how exploitable anything is, do not suggest scanning or testing these sites, and do not add findings that are not in the readings below. If a site is missing nothing, say so in one line. Readings: findings'. Save it as aiAnswer.
TextTrim aiAnswer.response_text and save it as explanationText.Trim aiAnswer.response_text and save it as explanationText.
On error
ValuesShow in the output: The readings could not be written up, so the email carries them as they are. explainError.message.Show in the output: The readings could not be written up, so the email carries them as they are. explainError.message.
ValuesSet emailIntro to Checked the length of siteReports of your sites. sitesWithGaps have something missing.Set emailIntro to Checked the length of siteReports of your sites. sitesWithGaps have something missing. Every site was read with one ordinary page request - the same headers a visitor's browser receives. Nothing was scanned or probed.
MathSet emailBody to emailIntro plus findings.Set emailBody to emailIntro plus findings.
Decisions & LoopsIf explanationText isn't emptyIf explanationText isn't empty
Yes
ValuesChange emailBody to emailIntro@explanationTextChange emailBody to emailIntro@explanationText --- What each site returned findings.
No
No steps
GmailGmailSend an email to reportEmail.Send an email to reportEmail. Subject: Website security headers: sitesWithGaps of the length of siteReports sites have gapsemailBody