Skip to content

Conversation

@KyleKing
Copy link
Owner

Security Improvements:

  • Add comprehensive security headers middleware (CSP, X-Frame-Options, X-Content-Type-Options, etc.)
  • Add SHA-256 integrity verification for HTMX downloads in build script
  • Add SECURITY.md documenting XSS protection via Vento autoescape

Dependencies:

  • Update Hono 4.9.8 → 4.10.6
  • Update Biome 2.2.4 → 2.3.6
  • Update Playwright 1.55.1 → 1.56.1
  • Update Zod 4.1.11 → 4.1.12
  • Update deno.lock with latest compatible versions

Performance:

  • Add aggressive cache headers for static assets (1 year, immutable)

User Experience:

  • Add favicon (SVG) for better branding
  • Add meta tags (description, theme-color, Open Graph) for social sharing

Documentation:

  • Expand README with environment variables, security practices, and architecture
  • Add SECURITY.md explaining XSS protection and security headers
  • Document that Vento autoescape is enabled for XSS prevention

All tests passing (27/27). Manual testing confirmed app functionality.

Security Improvements:
- Add comprehensive security headers middleware (CSP, X-Frame-Options, X-Content-Type-Options, etc.)
- Add SHA-256 integrity verification for HTMX downloads in build script
- Add SECURITY.md documenting XSS protection via Vento autoescape

Dependencies:
- Update Hono 4.9.8 → 4.10.6
- Update Biome 2.2.4 → 2.3.6
- Update Playwright 1.55.1 → 1.56.1
- Update Zod 4.1.11 → 4.1.12
- Update deno.lock with latest compatible versions

Performance:
- Add aggressive cache headers for static assets (1 year, immutable)

User Experience:
- Add favicon (SVG) for better branding
- Add meta tags (description, theme-color, Open Graph) for social sharing

Documentation:
- Expand README with environment variables, security practices, and architecture
- Add SECURITY.md explaining XSS protection and security headers
- Document that Vento autoescape is enabled for XSS prevention

All tests passing (27/27). Manual testing confirmed app functionality.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

src/app.ts Outdated
Comment on lines 124 to 126
onFound: (_path, c) => {
// Cache static assets for 1 year (immutable for hashed assets)
c.header("Cache-Control", "public, max-age=31536000, immutable")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Immutable caching applied to non-versioned static assets

The new onFound handler sets Cache-Control: public, max-age=31536000, immutable for every /public/* response, but the assets served there (styles.min.css, htmx.min.js, etc.) are not fingerprinted or versioned. Once a client loads the site, their browser will keep serving those old files for up to a year—even after new deployments—unless they manually clear cache or you change the URLs. That makes rolling out fixes or security updates to static assets effectively impossible for existing users.

Useful? React with 👍 / 👎.

@coderabbitai
Copy link

coderabbitai bot commented Jan 30, 2026

Walkthrough

This PR enhances project configuration, security posture, and documentation. It updates build tool and dependency versions (Biome, Playwright, Hono, Zod), adds a backup file ignore rule, and introduces new security documentation. Security middleware is implemented in the application to set protective HTTP headers and cache control policies. Asset downloading is hardened with SHA-256 integrity verification. Template metadata is expanded with description, theme color, Open Graph tags, and favicon references. README documentation is significantly extended with environment variables, security, and architecture sections.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In `@biome.json`:
- Line 2: Update the "$schema" value in biome.json to match the installed Biome
version by changing the URL from "https://biomejs.dev/schemas/2.3.6/schema.json"
to "https://biomejs.dev/schemas/2.3.13/schema.json" (or run the CLI migration
via `deno task biome migrate`) so the "$schema" field aligns with the Biome
version noted in deno.lock.

In `@scripts/download-assets.sh`:
- Around line 4-17: The checksum verification currently uses sha256sum which is
not available on macOS; modify the script to detect and use an available tool
(sha256sum or shasum -a 256) to verify HTMX_SHA256 against HTMX_FILE. Update the
verification block that references HTMX_SHA256 and HTMX_FILE so it first checks
for sha256sum, falls back to shasum -a 256 (adapting the input format if
needed), and fails with a clear error if neither is present; ensure the exit
behavior, file removal (rm -f "${HTMX_FILE}"), and error message remain the
same.

In `@SECURITY.md`:
- Around line 29-31: Update the SECURITY.md "Reporting Security Issues" section
to include a specific security contact and actionable links: add a dedicated
email address (e.g., [email protected]) for disclosure and a direct link
to the repository's GitHub Security Advisories or a SECURITY.md contact anchor
(e.g., "Report via GitHub Security Advisory:
https://github.com/OWNER/REPO/security/advisories") and mention preferred PGP
key or encrypted reporting instructions if available; ensure the new lines
replace or augment the current generic sentence so researchers have a clear
email and the GitHub advisories link to report vulnerabilities.
- Around line 17-23: Add the exact Content-Security-Policy string used in the
application into SECURITY.md under a "Content-Security-Policy" section: copy the
CSP value set in src/app.ts where the header is defined (the
res.setHeader('Content-Security-Policy', ...) / CSP middleware block) and
document each directive and its allowed sources (e.g., default-src, script-src,
style-src, img-src, connect-src, frame-ancestors, base-uri, form-action,
upgrade-insecure-requests, etc.) so the file contains the full header string and
a brief line-by-line explanation of each directive.
- Around line 5-13: Update the XSS Protection client-side guidance to match the
codebase: replace the reference to using textContent/innerHTML with the actual
escaping utility provided (escapeHtml in shared/commentShape.ts) or remove the
client-side reference entirely if no client-side guidance exists; specifically
edit the SECURITY.md XSS section so it either instructs developers to call
shared/commentShape.ts's escapeHtml before inserting user content or deletes the
incorrect textContent example to avoid misleading guidance.

In `@src/app.ts`:
- Around line 37-48: The security headers middleware (app.use("*", async (c,
next) => { ... })) currently sets headers only after await next(), so if
downstream throws the headers won't be applied; change it to set the headers
regardless by either setting them before calling await next() or wrapping await
next() in a try/finally and applying the headers in the finally block (ensure
you use the same header names: X-Content-Type-Options, X-Frame-Options,
X-XSS-Protection, Referrer-Policy, Content-Security-Policy so they are always
added to c.res.headers).

In `@src/templates/layouts/base.vto`:
- Around line 6-15: Add an Open Graph image meta tag to the base layout to
provide richer social previews: insert a meta property="og:image" that uses a
template variable (e.g., {{ image }} or a fallback such as
/public/og-default.png) alongside the existing og:title and og:description in
src/templates/layouts/base.vto; optionally also add a matching twitter:card and
twitter:image meta tag for improved Twitter previews, ensuring the image URL is
absolute or resolves correctly in production.

@@ -1,5 +1,5 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.4/schema.json",
"$schema": "https://biomejs.dev/schemas/2.3.6/schema.json",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find package.json or similar files that declare Biome version
fd -e json -e yaml -e yml | head -20

Repository: KyleKing/app-template

Length of output: 97


🏁 Script executed:

# Check for Biome version in package.json
if [ -f "package.json" ]; then
  cat -n package.json | grep -i biome
fi

Repository: KyleKing/app-template

Length of output: 47


🏁 Script executed:

# Also check if there's a lockfile that might indicate Biome version
ls -la | grep -E "(package-lock|yarn.lock|pnpm-lock)"

Repository: KyleKing/app-template

Length of output: 47


🌐 Web query:

Biome 2.3.6 schema URL validity and documentation

💡 Result:

Is the Biome 2.3.6 $schema URL valid?

Yes. The versioned schema endpoint exists and returns JSON Schema (draft 2020-12):

{
  "$schema": "https://biomejs.dev/schemas/2.3.6/schema.json"
}

This URL serves a JSON schema document for biome.json / biome.jsonc. (biomejs.dev)

What’s the “official” way to reference the schema?

Biome documents two supported approaches:

  1. Local schema from the installed npm package (no network dependency):
{
  "$schema": "./node_modules/@biomejs/biome/configuration_schema.json"
}
``` ([biomejs.dev](https://biomejs.dev/reference/configuration/?utm_source=openai))

2) **Remote, versioned schema hosted on biomejs.dev**:
```jsonc
{
  "$schema": "https://biomejs.dev/schemas/<version>/schema.json"
}
``` ([biomejs.dev](https://biomejs.dev/reference/configuration/?utm_source=openai))

## Documentation pointers
- `$schema` field + examples: Biome “Configuration” reference. ([biomejs.dev](https://biomejs.dev/reference/configuration/?utm_source=openai))  
- Broader config structure & examples: “Configure Biome” guide. ([biomejs.dev](https://biomejs.dev/guides/configure-biome?utm_source=openai))

## Notes on version matching
Biome tracks the schema URL version and may warn when the `$schema` version doesn’t match the CLI version; the project recommends using `biome migrate` to update/migrate configs when upgrading. ([github.com](https://github.com/biomejs/biome/issues/4147?utm_source=openai))

Citations:

- 1: https://biomejs.dev/schemas/2.3.6/schema.json
- 2: https://biomejs.dev/reference/configuration/?utm_source=openai
- 3: https://biomejs.dev/reference/configuration/?utm_source=openai
- 4: https://biomejs.dev/reference/configuration/?utm_source=openai
- 5: https://biomejs.dev/guides/configure-biome?utm_source=openai
- 6: https://github.com/biomejs/biome/issues/4147?utm_source=openai

---

🌐 Web query:

`Biome breaking changes between version 2.2.4 and 2.3.6`

💡 Result:

Between **Biome 2.2.42.3.6**, there are **no explicitly labeled “BREAKING CHANGES”** in the official v2.x changelog entries for those releases. **2.2.4** itself is patch-only fixes/features. [1]

That said, there are a few **behavior/output changes** in **2.3.02.3.5** that commonly *act* like breaking changes in real projects:

- **Rule auto-enablement via “installed dependencies” changed (2.3.0):** rules in a domain are **no longer auto-enabled** by installed dependencies **unless the rule is “recommended”**. This can reduce the set of rules that run after upgrading (or change which diagnostics you see). [2]
- **Formatter output changes for `.svelte` / `.vue` (2.3.0):** indentation of JavaScript blocks was updated to match Prettier’s behavior, which can change formatted output and snapshot diffs. [2]
- **If you enabled experimental Vue full support (2.3.5):** the HTML parser gained the ability to parse Vue directives, and the changelog notes this **may introduce parsing errors where there were none before** for those opted into `experimentalFullSupportEnabled`. [3]

Everything in **2.3.6** is listed as patch changes (new nursery rules + fixes), with no breaking-change callouts. [4]

**Sources:**  
[1] Biome 2.2.4 changelog entry. ([biomejs.dev](https://biomejs.dev/internals/changelog/version/2-2-4/?utm_source=openai))  
[2] Biome 2.3.0 changelog entry (rule auto-enable change; formatter changes). ([biomejs.dev](https://biomejs.dev/internals/changelog/version/2-3-0/))  
[3] Biome 2.3.5 changelog entry (Vue directives parsing note). ([biomejs.dev](https://biomejs.dev/internals/changelog/version/2-3-5/))  
[4] Biome 2.3.6 changelog entry. ([chat.biomejs.dev](https://chat.biomejs.dev/internals/changelog/version/2-3-1...latest/?utm_source=openai))

Citations:

- 1: https://biomejs.dev/internals/changelog/version/2-2-4/?utm_source=openai
- 2: https://biomejs.dev/internals/changelog/version/2-3-0/
- 3: https://biomejs.dev/internals/changelog/version/2-3-5/
- 4: https://chat.biomejs.dev/internals/changelog/version/2-3-1...latest/?utm_source=openai

---

🏁 Script executed:

```shell
cat biome.json

Repository: KyleKing/app-template

Length of output: 1062


🏁 Script executed:

# Check for Biome version more broadly in configuration files
rg -i "biome" -A 2 -B 2 | head -40

Repository: KyleKing/app-template

Length of output: 2001


Update schema version to match installed Biome version.
The schema URL https://biomejs.dev/schemas/2.3.6/schema.json is valid, but the project uses Biome 2.3.13 (from deno.lock). Update the schema to https://biomejs.dev/schemas/2.3.13/schema.json or run deno task biome migrate to align the configuration with the installed version. Biome may warn when the schema version mismatches the CLI version.

🤖 Prompt for AI Agents
In `@biome.json` at line 2, Update the "$schema" value in biome.json to match the
installed Biome version by changing the URL from
"https://biomejs.dev/schemas/2.3.6/schema.json" to
"https://biomejs.dev/schemas/2.3.13/schema.json" (or run the CLI migration via
`deno task biome migrate`) so the "$schema" field aligns with the Biome version
noted in deno.lock.

Comment on lines +4 to +17
HTMX_VERSION="2.0.6"
HTMX_URL="https://cdn.jsdelivr.net/npm/htmx.org@${HTMX_VERSION}/dist/htmx.min.js"
HTMX_SHA256="b6768eed4f3af85b73a75054701bd60e17cac718aef2b7f6b254e5e0e2045616"
HTMX_FILE="public/htmx.min.js"

echo "Downloading HTMX ${HTMX_VERSION}..."
curl -fsSL -o "${HTMX_FILE}" "${HTMX_URL}"

echo "Verifying integrity..."
echo "${HTMX_SHA256} ${HTMX_FILE}" | sha256sum -c - || {
echo "ERROR: Integrity check failed for ${HTMX_FILE}"
rm -f "${HTMX_FILE}"
exit 1
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make checksum verification portable across macOS/Linux.

Proposed fix
-echo "${HTMX_SHA256}  ${HTMX_FILE}" | sha256sum -c - || {
+if command -v sha256sum >/dev/null 2>&1; then
+  echo "${HTMX_SHA256}  ${HTMX_FILE}" | sha256sum -c -
+else
+  echo "${HTMX_SHA256}  ${HTMX_FILE}" | shasum -a 256 -c -
+fi || {
   echo "ERROR: Integrity check failed for ${HTMX_FILE}"
   rm -f "${HTMX_FILE}"
   exit 1
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
HTMX_VERSION="2.0.6"
HTMX_URL="https://cdn.jsdelivr.net/npm/htmx.org@${HTMX_VERSION}/dist/htmx.min.js"
HTMX_SHA256="b6768eed4f3af85b73a75054701bd60e17cac718aef2b7f6b254e5e0e2045616"
HTMX_FILE="public/htmx.min.js"
echo "Downloading HTMX ${HTMX_VERSION}..."
curl -fsSL -o "${HTMX_FILE}" "${HTMX_URL}"
echo "Verifying integrity..."
echo "${HTMX_SHA256} ${HTMX_FILE}" | sha256sum -c - || {
echo "ERROR: Integrity check failed for ${HTMX_FILE}"
rm -f "${HTMX_FILE}"
exit 1
}
HTMX_VERSION="2.0.6"
HTMX_URL="https://cdn.jsdelivr.net/npm/htmx.org@${HTMX_VERSION}/dist/htmx.min.js"
HTMX_SHA256="b6768eed4f3af85b73a75054701bd60e17cac718aef2b7f6b254e5e0e2045616"
HTMX_FILE="public/htmx.min.js"
echo "Downloading HTMX ${HTMX_VERSION}..."
curl -fsSL -o "${HTMX_FILE}" "${HTMX_URL}"
echo "Verifying integrity..."
if command -v sha256sum >/dev/null 2>&1; then
echo "${HTMX_SHA256} ${HTMX_FILE}" | sha256sum -c -
else
echo "${HTMX_SHA256} ${HTMX_FILE}" | shasum -a 256 -c -
fi || {
echo "ERROR: Integrity check failed for ${HTMX_FILE}"
rm -f "${HTMX_FILE}"
exit 1
}
🤖 Prompt for AI Agents
In `@scripts/download-assets.sh` around lines 4 - 17, The checksum verification
currently uses sha256sum which is not available on macOS; modify the script to
detect and use an available tool (sha256sum or shasum -a 256) to verify
HTMX_SHA256 against HTMX_FILE. Update the verification block that references
HTMX_SHA256 and HTMX_FILE so it first checks for sha256sum, falls back to shasum
-a 256 (adapting the input format if needed), and fails with a clear error if
neither is present; ensure the exit behavior, file removal (rm -f
"${HTMX_FILE}"), and error message remain the same.

Comment on lines +5 to +13
This application uses **Vento templating engine** with `autoescape: true` (configured in `src/templates/engine.ts`). This automatically escapes all template variables to prevent Cross-Site Scripting (XSS) attacks.

**Important:** Vento's autoescape defaults to `false`, so it must be explicitly enabled. This project has it properly configured for security.

### Safe Usage

- Template variables are automatically escaped: `{{ comment.body }}` is safe
- Use the `|> safe` filter only for trusted, already-sanitized content
- Client-side: Use `textContent` instead of `innerHTML` for user input (see `shared/commentShape.ts`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and display referenced security configuration files

echo "=== Checking for src/templates/engine.ts ==="
fd -t f "engine.ts" --exec cat {} 2>/dev/null || echo "Not found"

echo -e "\n=== Checking for shared/commentShape.ts ==="
fd -t f "commentShape.ts" --exec cat {} 2>/dev/null || echo "Not found"

echo -e "\n=== Checking for src/app.ts ==="
fd -t f "app.ts" src/ --exec cat {} 2>/dev/null | head -100 || echo "Not found"

echo -e "\n=== Checking for scripts/download-assets.sh ==="
fd -t f "download-assets.sh" --exec cat {} 2>/dev/null || echo "Not found"

echo -e "\n=== Checking for SECURITY.md ==="
fd -t f "SECURITY.md" --exec wc -l {} \;

Repository: KyleKing/app-template

Length of output: 5709


🌐 Web query:

Vento templating engine autoescape default setting

💡 Result:

In Vento, autoescaping is disabled by default (autoescape: false). You must explicitly enable it in the environment options (e.g., vento({ autoescape: true })) if you want variables to be HTML-escaped automatically. [1][2]


Update the client-side example in the XSS Protection section.

The referenced files are properly configured: src/templates/engine.ts correctly enables Vento's autoescape, security headers are implemented in src/app.ts, and asset integrity verification is in place. However, shared/commentShape.ts provides an escapeHtml() function for server-side escaping but does not contain guidance on using textContent instead of innerHTML. Replace the client-side reference with the actual escaping method used, or remove the reference if client-side guidance isn't documented elsewhere.

🤖 Prompt for AI Agents
In `@SECURITY.md` around lines 5 - 13, Update the XSS Protection client-side
guidance to match the codebase: replace the reference to using
textContent/innerHTML with the actual escaping utility provided (escapeHtml in
shared/commentShape.ts) or remove the client-side reference entirely if no
client-side guidance exists; specifically edit the SECURITY.md XSS section so it
either instructs developers to call shared/commentShape.ts's escapeHtml before
inserting user content or deletes the incorrect textContent example to avoid
misleading guidance.

Comment on lines +17 to +23
The application includes security headers middleware (see `src/app.ts`):

- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `X-XSS-Protection: 1; mode=block`
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Content-Security-Policy` with restricted directives
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "app.ts" | head -20

Repository: KyleKing/app-template

Length of output: 77


🏁 Script executed:

# Search for security headers middleware
rg -n "X-Content-Type-Options|X-Frame-Options|X-XSS-Protection|Referrer-Policy|Content-Security-Policy" --type ts

Repository: KyleKing/app-template

Length of output: 400


🏁 Script executed:

# Check src/app.ts content if it exists
ls -la src/app.ts 2>/dev/null && wc -l src/app.ts

Repository: KyleKing/app-template

Length of output: 139


🏁 Script executed:

sed -n '40,60p' src/app.ts

Repository: KyleKing/app-template

Length of output: 846


🏁 Script executed:

# Check SECURITY.md for CSP directive documentation
cat -n SECURITY.md

Repository: KyleKing/app-template

Length of output: 1522


Document CSP directives in SECURITY.md for transparency.

All security headers are correctly implemented in src/app.ts. However, the CSP directive details (lines 45-47 in src/app.ts) should be documented in SECURITY.md to make the actual policy explicit:

Suggested CSP directive documentation
 - `Content-Security-Policy` with restricted directives
+  - `default-src 'self'`
+  - `script-src 'self' 'unsafe-inline'`
+  - `style-src 'self' 'unsafe-inline'`
+  - `img-src 'self' data:`
+  - `font-src 'self'`
+  - `connect-src 'self'`
+  - `frame-ancestors 'none'`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The application includes security headers middleware (see `src/app.ts`):
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `X-XSS-Protection: 1; mode=block`
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Content-Security-Policy` with restricted directives
The application includes security headers middleware (see `src/app.ts`):
- `X-Content-Type-Options: nosniff`
- `X-Frame-Options: DENY`
- `X-XSS-Protection: 1; mode=block`
- `Referrer-Policy: strict-origin-when-cross-origin`
- `Content-Security-Policy`:
- `default-src 'self'`
- `script-src 'self' 'unsafe-inline'`
- `style-src 'self' 'unsafe-inline'`
- `img-src 'self' data:`
- `font-src 'self'`
- `connect-src 'self'`
- `frame-ancestors 'none'`
🤖 Prompt for AI Agents
In `@SECURITY.md` around lines 17 - 23, Add the exact Content-Security-Policy
string used in the application into SECURITY.md under a
"Content-Security-Policy" section: copy the CSP value set in src/app.ts where
the header is defined (the res.setHeader('Content-Security-Policy', ...) / CSP
middleware block) and document each directive and its allowed sources (e.g.,
default-src, script-src, style-src, img-src, connect-src, frame-ancestors,
base-uri, form-action, upgrade-insecure-requests, etc.) so the file contains the
full header string and a brief line-by-line explanation of each directive.

Comment on lines +29 to +31
## Reporting Security Issues

If you discover a security vulnerability, please email the maintainers or open a private security advisory on GitHub.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding specific contact information.

While the guidance is good, providing a specific security contact email or GitHub security advisory link would make it more actionable for security researchers.

💡 Suggested improvement
-If you discover a security vulnerability, please email the maintainers or open a private security advisory on GitHub.
+If you discover a security vulnerability, please:
+
+1. Open a [private security advisory](https://github.com/KyleKing/app-template/security/advisories/new) on GitHub (preferred)
+2. Or email: [[email protected]] (if available)
+
+Please do not disclose security issues publicly until they have been addressed.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Reporting Security Issues
If you discover a security vulnerability, please email the maintainers or open a private security advisory on GitHub.
## Reporting Security Issues
If you discover a security vulnerability, please:
1. Open a [private security advisory](https://github.com/KyleKing/app-template/security/advisories/new) on GitHub (preferred)
2. Or email: [[email protected]] (if available)
Please do not disclose security issues publicly until they have been addressed.
🤖 Prompt for AI Agents
In `@SECURITY.md` around lines 29 - 31, Update the SECURITY.md "Reporting Security
Issues" section to include a specific security contact and actionable links: add
a dedicated email address (e.g., [email protected]) for disclosure and a
direct link to the repository's GitHub Security Advisories or a SECURITY.md
contact anchor (e.g., "Report via GitHub Security Advisory:
https://github.com/OWNER/REPO/security/advisories") and mention preferred PGP
key or encrypted reporting instructions if available; ensure the new lines
replace or augment the current generic sentence so researchers have a clear
email and the GitHub advisories link to report vulnerabilities.

Comment on lines +37 to +48
// Security headers middleware
app.use("*", async (c, next) => {
await next()
c.res.headers.set("X-Content-Type-Options", "nosniff")
c.res.headers.set("X-Frame-Options", "DENY")
c.res.headers.set("X-XSS-Protection", "1; mode=block")
c.res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin")
c.res.headers.set(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",
)
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Ensure security headers are set even when downstream throws.

Proposed fix
 app.use("*", async (c, next) => {
-  await next()
-  c.res.headers.set("X-Content-Type-Options", "nosniff")
-  c.res.headers.set("X-Frame-Options", "DENY")
-  c.res.headers.set("X-XSS-Protection", "1; mode=block")
-  c.res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin")
-  c.res.headers.set(
-    "Content-Security-Policy",
-    "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",
-  )
+  try {
+    await next()
+  } finally {
+    c.res.headers.set("X-Content-Type-Options", "nosniff")
+    c.res.headers.set("X-Frame-Options", "DENY")
+    c.res.headers.set("X-XSS-Protection", "1; mode=block")
+    c.res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin")
+    c.res.headers.set(
+      "Content-Security-Policy",
+      "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",
+    )
+  }
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Security headers middleware
app.use("*", async (c, next) => {
await next()
c.res.headers.set("X-Content-Type-Options", "nosniff")
c.res.headers.set("X-Frame-Options", "DENY")
c.res.headers.set("X-XSS-Protection", "1; mode=block")
c.res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin")
c.res.headers.set(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",
)
})
// Security headers middleware
app.use("*", async (c, next) => {
try {
await next()
} finally {
c.res.headers.set("X-Content-Type-Options", "nosniff")
c.res.headers.set("X-Frame-Options", "DENY")
c.res.headers.set("X-XSS-Protection", "1; mode=block")
c.res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin")
c.res.headers.set(
"Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'",
)
}
})
🤖 Prompt for AI Agents
In `@src/app.ts` around lines 37 - 48, The security headers middleware
(app.use("*", async (c, next) => { ... })) currently sets headers only after
await next(), so if downstream throws the headers won't be applied; change it to
set the headers regardless by either setting them before calling await next() or
wrapping await next() in a try/finally and applying the headers in the finally
block (ensure you use the same header names: X-Content-Type-Options,
X-Frame-Options, X-XSS-Protection, Referrer-Policy, Content-Security-Policy so
they are always added to c.res.headers).

Comment on lines +6 to +15
<meta name="description" content="A modern Deno web application template with Hono, Vento, and HTMX">
<meta name="theme-color" content="#2563eb">

<!-- Open Graph / Social Media -->
<meta property="og:type" content="website">
<meta property="og:title" content="{{ title }}">
<meta property="og:description" content="A modern Deno web application template">

<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/public/favicon.svg">
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider adding og:image for richer social previews.

Suggested addition
     <!-- Open Graph / Social Media -->
     <meta property="og:type" content="website">
     <meta property="og:title" content="{{ title }}">
     <meta property="og:description" content="A modern Deno web application template">
+    <meta property="og:image" content="/public/og-image.png">
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<meta name="description" content="A modern Deno web application template with Hono, Vento, and HTMX">
<meta name="theme-color" content="#2563eb">
<!-- Open Graph / Social Media -->
<meta property="og:type" content="website">
<meta property="og:title" content="{{ title }}">
<meta property="og:description" content="A modern Deno web application template">
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/public/favicon.svg">
<meta name="description" content="A modern Deno web application template with Hono, Vento, and HTMX">
<meta name="theme-color" content="#2563eb">
<!-- Open Graph / Social Media -->
<meta property="og:type" content="website">
<meta property="og:title" content="{{ title }}">
<meta property="og:description" content="A modern Deno web application template">
<meta property="og:image" content="/public/og-image.png">
<!-- Favicon -->
<link rel="icon" type="image/svg+xml" href="/public/favicon.svg">
🤖 Prompt for AI Agents
In `@src/templates/layouts/base.vto` around lines 6 - 15, Add an Open Graph image
meta tag to the base layout to provide richer social previews: insert a meta
property="og:image" that uses a template variable (e.g., {{ image }} or a
fallback such as /public/og-default.png) alongside the existing og:title and
og:description in src/templates/layouts/base.vto; optionally also add a matching
twitter:card and twitter:image meta tag for improved Twitter previews, ensuring
the image URL is absolute or resolves correctly in production.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants