agentsclimarketplace

Audit security

Skill magallon/website-audit-toolkit/audit-security

Security audit for static websites hosted on cPanel with vanilla HTML/CSS/JS that communicate with external webhooks. Reviews security headers in .htaccess (CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy), sensitive file protection on cPanel, information exposure in client-side code, XSS when inserting webhook responses into the DOM, CORS configuration on external webhooks, file permissions on the server, error handling without information leakage, and hotlinking protection. Run as the eighth audit in the pre-production protocol, after performance, code consistency, accessibility, responsive design, cross-browser, conversion UX, and SEO.From its SKILL.md

Install
npx -y skills add magallon/website-audit-toolkit --skill audit-security

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.8 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it

Security Audit

Static Websites on cPanel — External Webhook Integration

A static marketing site has a significantly smaller attack surface than a web application with a backend. There is no database to inject, no authentication to break, no sessions to hijack. However, specific vulnerabilities exist in this context — a public site on shared hosting with external webhooks — that must be verified before launch.

Scope: static marketing site + interactive demo with external webhook integration.

Out of scope: backend platform vulnerabilities (user authentication, data isolation, role permissions). That requires a separate audit of the production system.


Severity Levels

LevelDescriptionAction
CriticalSensitive data exposure or exploitable attack vectorFix before launch
HighSignificant security weakness without obvious immediate exploitFix before launch
MediumSuboptimal configuration that reduces security postureFix in first week
LowBest practice improvement with minor impactFix when convenient

Section 1 — Security Headers in .htaccess

HTTP security headers are the first line of defense for a static site. Configured in .htaccess at site root on cPanel. No backend required — these are Apache server instructions.

1.1 Complete Header Configuration

<IfModule mod_headers.c>

  # HSTS — forces HTTPS, prevents downgrade attacks
  Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"

  # Prevents clickjacking — blocks site from loading in iframe
  Header always set X-Frame-Options "DENY"

  # Prevents MIME sniffing — browser respects declared Content-Type
  Header always set X-Content-Type-Options "nosniff"

  # Controls information sent in Referer header
  Header always set Referrer-Policy "strict-origin-when-cross-origin"

  # Disables browser APIs not needed by the site
  Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()"

  # Content Security Policy — defines which resources the browser can load
  # Adjust domains to match actual resources used (fonts, analytics, webhooks)
  Header always set Content-Security-Policy "\
    default-src 'self'; \
    script-src 'self' 'unsafe-inline'; \
    style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; \
    font-src 'self' https://fonts.gstatic.com; \
    img-src 'self' data: https:; \
    connect-src 'self' https://[webhook-domain]; \
    frame-ancestors 'none'; \
    base-uri 'self'; \
    form-action 'self' https://[webhook-domain]"

</IfModule>

CSP notes:

  • 'unsafe-inline' in script-src and style-src is needed if JS/CSS is inline. For better security, move all JS to external files and remove 'unsafe-inline' from script-src
  • If third-party analytics are used (Google Analytics, Hotjar), add their domain to script-src
  • connect-src must include the exact webhook URL — not a wildcard

What to check:

  • .htaccess exists at site root
  • Strict-Transport-Security set with minimum 1 year
  • X-Frame-Options set to DENY or SAMEORIGIN
  • X-Content-Type-Options set to nosniff
  • Referrer-Policy configured
  • Permissions-Policy disables unused APIs
  • Content-Security-Policy configured — does not use default-src *
  • connect-src includes exact webhook domain, not wildcard
  • Verify with: https://securityheaders.com

1.2 HTTPS Redirect

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

What to check:

  • HTTP redirects to HTTPS
  • www/non-www redirects to chosen convention
  • Redirect is 301 (permanent), not 302 (temporary)
  • No redirect loops

Section 2 — File Protection on cPanel

A cPanel shared server makes all files inside public_html publicly accessible by default. Sensitive files must be explicitly protected.

2.1 Files That Must Never Be Public

# Block access to configuration and sensitive files
<FilesMatch "\.(env|json|md|log|sh|py|sql|bak|backup|zip|tar|gz)$">
  Order allow,deny
  Deny from all
</FilesMatch>

# Block hidden files (starting with dot)
<FilesMatch "^\.">
  Order allow,deny
  Deny from all
</FilesMatch>

What to check:

  • No .env files inside public_html
  • No config.json with sensitive data in public_html
  • No backups (.zip, .tar.gz, backup_, _old) in public_html
  • No publicly accessible log files
  • .htaccess blocks access to sensitive extensions
  • Verify: https://[domain]/.env must return 403

2.2 Directory Listing

Options -Indexes

Without this, Apache shows a file listing for directories without index.html, exposing site structure.

What to check:

  • Options -Indexes in .htaccess
  • Verify: https://[domain]/assets/ returns 403 or redirect, not a file listing

2.3 File Permissions

TypePermissionOctal
HTML, CSS, JS, imagesOwner read/write, others read-only644
.htaccessOwner read/write, others read-only644
DirectoriesOwner rwx, others rx755
Sensitive config filesOwner read/write only600

What to check:

  • HTML/CSS/JS files have 644 permissions
  • Directories have 755 permissions
  • No file has 777 permissions
  • .htaccess has 644, not 777

Section 3 — Information Exposure in Client-Side Code

All JavaScript in a static site is publicly visible. Any visitor can view source or open DevTools and read the complete code.

3.1 API Keys and Secrets in JavaScript

// ❌ CRITICAL — visible to any visitor
const OPENAI_API_KEY = 'sk-proj-abc123...'
const WEBHOOK_SECRET = 'my-secret-token-xyz'

// ✅ CORRECT — client only calls the public webhook
// The webhook acts as proxy and holds server-side secrets
const WEBHOOK_URL = 'https://[webhook-domain]/webhook/demo'

Correct architecture: Client JS calls webhook with user query → webhook server calls APIs with server-side keys → webhook returns response to client. The client never sees API keys.

What to check:

  • Search all .js and HTML files: no strings starting with sk-, Bearer , api_key, apikey, secret, token followed by a literal value
  • Webhook URL can be public — it's the entry endpoint, not the secret
  • If an auth header exists in the fetch call, verify it's a limited-use token, not a production API key
  • No cPanel, FTP, or email credentials in any JS file

3.2 Internal URLs and Infrastructure Data

What to check:

  • No internal service URLs (databases, vector stores, internal APIs) in client JS
  • No internal server IPs in code
  • Development comments contain no sensitive information

3.3 Development Comments

What to check:

  • Search all JS and HTML: TODO, FIXME, HACK, password, credential, key, token followed by values
  • Remaining comments are code explanations, not infrastructure data

Section 4 — Interactive Demo Security

If the project does not include an interactive demo with webhook integration, skip this section.

The demo receives user input, calls an external webhook, and inserts the response into the DOM. These three operations have specific attack vectors.

4.1 XSS When Inserting Responses

// ❌ CRITICAL — XSS if response contains  or HTML tags
container.innerHTML = data.response

// ✅ For plain text responses
container.textContent = data.response

// ✅ For formatted responses — sanitize first
container.innerHTML = DOMPurify.sanitize(data.response, {
  ALLOWED_TAGS: ['b', 'strong', 'em', 'p', 'br', 'ul', 'li'],
  ALLOWED_ATTR: []
})

What to check:

  • No innerHTML directly assigns a webhook/fetch response
  • If innerHTML is used, response passes through sanitization first
  • Error messages also use textContent, not innerHTML

4.2 User Input Validation

// ✅ Validate before sending to webhook
async function sendQuery() {
  const query = document.getElementById('demo-input').value.trim()

  if (!query) return showError('Please enter a question')
  if (query.length > 500) return showError('Question too long (max 500 characters)')
  if (!/\w/.test(query)) return showError('Please enter a valid question')

  // Proceed with fetch...
}

What to check:

  • Input validates non-empty before calling webhook
  • Input has maximum length limit (HTML maxlength + JS validation)
  • Submit button disabled during pending request — prevents multiple simultaneous calls
  • User-facing error messages are generic — no webhook URLs or technical errors exposed

4.3 Client-Side Rate Limiting

Without rate limiting, a user or bot can make hundreds of webhook calls, generating API costs.

let lastRequestTime = 0
const MIN_REQUEST_INTERVAL = 3000

async function sendQuery() {
  const now = Date.now()
  if (now - lastRequestTime < MIN_REQUEST_INTERVAL) {
    return showError('Please wait a moment before searching again')
  }
  lastRequestTime = now
  // Continue with fetch...
}

Note: Client-side rate limiting is a courtesy measure, not real security — an attacker can bypass it. Real rate limiting must be configured on the webhook server.


Section 5 — Webhook CORS Configuration

CORS controls which domains can call the webhook. Without correct configuration, any website could call the project's webhook. Correct — specific origin Access-Control-Allow-Origin: https://[project-domain] Access-Control-Allow-Methods: POST, OPTIONS Access-Control-Allow-Headers: Content-Type NEVER use wildcard Access-Control-Allow-Origin: *

What to check:

  • Webhook responds with specific Access-Control-Allow-Origin — not *
  • CORS only allows necessary methods (POST for demo)
  • Verify in DevTools → Network → webhook call → check response headers
  • If a staging subdomain exists, it is included in allowed origins

Section 6 — Hotlinking Protection

Hotlinking occurs when other sites link directly to the project's images or resources, using its bandwidth.

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?[project-domain] [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp|svg|mp4|pdf)$ - [F,NC]

What to check:

  • Protection allows empty referer (direct access) and own domain
  • Resources needed for social sharing (og:image) are excluded or protection doesn't block them

Section 7 — Error Handling Without Information Leakage

// ❌ Exposes internal information
catch (error) {
  showError(`Error: ${error.message}`)
}

// ✅ Generic message for user, technical log in console
catch (error) {
  console.error('[Demo] Query processing error:', error)
  showError('Unable to process your query right now. Please try again.')
}

What to check:

  • User-facing error messages are generic and in the site's language
  • No error message includes URLs, filenames, stack traces, or technical error codes
  • Technical errors logged to console.error (useful for debugging) but not shown in UI
  • Error UI has a clear, actionable message: what to do next

Audit Output Format

Security Audit — [Project Name]
Date: [Date]
Summary

Critical issues: X
High priority: X
Medium priority: X
Low priority: X
Security headers grade: [A+ / A / B / C / D / F] (via securityheaders.com)
Overall security posture: [Solid / Needs work / Critical vulnerabilities]

Critical Issues
[Issue title]

Category: [Headers / File protection / Information exposure / XSS / CORS / Permissions]
File: [filename and line]
Issue: [What is exposed or vulnerable]
Fix: [Specific correction]

High Priority
[Same format]
Medium Priority
[Same format]
Low Priority
[Same format]
Recommended Fix Order

API keys and credentials in client code — immediate data exposure
XSS in DOM insertion — active attack vector
CORS wildcard on webhook — unauthorized access
Security headers — defense in depth
File permissions and access — server hardening
Rate limiting and input validation — abuse prevention

Full pre-launch checklist and tools reference: see references/checklist.md

What ships with it: 1 file

1.9 KB alongside SKILL.md

references/

Keep looking

Skills are one crate of 326,835. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.