Skip to content

MEIER-352: Fix WAF case-sensitive bypass and switch Serilog to OTLP sink#85

Merged
andymeierdev merged 1 commit intomainfrom
andymeierdev/MEIER-352/fix-waf-case-bypass-and-otel-logs
Mar 24, 2026
Merged

MEIER-352: Fix WAF case-sensitive bypass and switch Serilog to OTLP sink#85
andymeierdev merged 1 commit intomainfrom
andymeierdev/MEIER-352/fix-waf-case-bypass-and-otel-logs

Conversation

@andymeierdev
Copy link
Copy Markdown
Collaborator

Summary

Two fixes to improve observability and security for andymeier.dev:

1. WAF case-sensitive bypass fix (pulumi/src/cloudflare/waf.ts)

Vulnerability scanners were using mixed-case paths (e.g. /ReAcT/.EnV, /StAgInG/.EnV, /.eNv.sAvE.1) to bypass the Cloudflare WAF rules, which used case-sensitive contains matching.

Fix: Wrapped every expression in lower() so lower(http.request.uri.path) contains "/.env" catches all case variants. Also added a rule for .env. variants (.env.sample, .env.prod, .env.save.1) and deduplicated the phpMyAdmin entries.

2. Switch Serilog to OTLP sink (app/src/App/src/Program.fs, app/src/App/paket.references)

Serilog log events sent to Seq via the Seq sink had no service identifier, making it impossible to distinguish logs from andymeier vs fsharpviewengine or other .NET apps. Meanwhile, OTLP traces already included Resource.service.name = "andymeier".

Fix: Replaced Serilog.Sinks.Seq with Serilog.Sinks.OpenTelemetry, which sends logs via OTLP with Resource.service.name = "andymeier" — matching the standard already used by traces. Removed the unused Seq sink dependency.

Tradeoff: The Seq sink supported controlLevelSwitch for remote log level adjustment from the Seq UI. The OTel sink does not — log level is now controlled only by the DEBUG env var.

Validation

  • All 61 tests pass (./fake.sh Test)
  • pulumi preview shows expected changes (WAF ruleset update + deployment update)
  • Confirmed via Seq API that existing log events lack service identification and traces have it via Resource.service.name

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 24, 2026

🍹 preview on andymeier/prod

Pulumi report

View in Pulumi Cloud

  Previewing update (prod)

View Live: https://app.pulumi.com/meiermade/andymeier/prod/previews/5cdd96b7-c624-4f54-939d-2c8229fa6787

pulumi:pulumi:Stack: (same)
  [urn=urn:pulumi:prod::andymeier::pulumi:pulumi:Stack::andymeier-prod]
  ~ docker-build:index:Image: (update)
      [id=sha256:4220b7870863d07b1de96b565c6d5b26306a51590b5d515cb44734e64b92fa6a]
      [urn=urn:pulumi:prod::andymeier::docker-build:index:Image::andymeier]
    - contextHash: "ece35dd35436d92ff2c16906a7a6ec12a16876c97a7799ac435e2469829a889f"
  ~ kubernetes:apps/v1:Deployment: (update)
      [id=andymeier/app]
      [urn=urn:pulumi:prod::andymeier::kubernetes:apps/v1:Deployment::app]
    ~ spec: {
        ~ template: {
            ~ spec: {
                ~ containers: [
                    ~ [0]: {
                            ~ image: "us-east1-docker.pkg.dev/meiermade-platform/platform/andymeier:latest@sha256:42cac190328476f0df00b02e7208c85b76da0ba61e767f9c090eab98308e53fe" => [unknown]
                          }
                  ]
              }
          }
      }
  ~ cloudflare:index/ruleset:Ruleset: (update)
      [id=7789caeecaa644cbb24b93c65c800064]
      [urn=urn:pulumi:prod::andymeier::cloudflare:index/ruleset:Ruleset::andymeier-waf]
    ~ rules: [
        ~ [0]: {
                  action     : "block"
                  description: "Block common vulnerability scanner paths and file extensions"
                  enabled    : true
                ~ expression : "(http.request.uri.path contains \"/.env\") or (http.request.uri.path contains \"/.git\") or (http.request.uri.path contains \"/.aws\") or (http.request.uri.path contains \"/.ssh\") or (http.request.uri.path contains \"/.terraform\") or (http.request.uri.path contains \"/wp-\") or (http.request.uri.path contains \"/wordpress\") or (http.request.uri.path contains \"/xmlrpc\") or (http.request.uri.path contains \"/phpMyAdmin\") or (http.request.uri.path contains \"/phpmyadmin\") or (http.request.uri.path contains \"/pma\") or (http.request.uri.path contains \"/admin\") or (http.request.uri.path contains \"/cgi-bin\") or (http.request.uri.path contains \"/actuator\") or (http.request.uri.path contains \"/solr\") or (http.request.uri.path contains \"/telescope\") or (http.request.uri.path contains \"/vendor\") or (http.request.uri.path contains \"/invoker\") or (http.request.uri.path contains \"/balancer-manager\") or (http.request.uri.path contains \"/credentials\") or (http.request.uri.path contains \"/known_hosts\") or (http.request.uri.path contains \"sendgrid\") or (http.request.uri.path contains \"codecommit\") or (http.request.uri.path contains \"/env.cfg\") or (http.request.uri.path contains \".php\") or (http.request.uri.path contains \".asp\") or (http.request.uri.path contains \".jsp\") or (http.request.uri.path contains \".cgi\") or (http.request.uri.path contains \".yml\") or (http.request.uri.path contains \".xml\") or (http.request.uri.path contains \".bak\") or (http.request.uri.path contains \".rb\")" => "(lower(url_decode(http.request.uri.path)) contains \"/.env\") or (lower(url_decode(http.request.uri.path)) contains \"/.git\") or (lower(url_decode(http.request.uri.path)) contains \"/.aws\") or (lower(url_decode(http.request.uri.path)) contains \"/.ssh\") or (lower(url_decode(http.request.uri.path)) contains \"/.terraform\") or (lower(url_decode(http.request.uri.path)) contains \"/wp-\") or (lower(url_decode(http.request.uri.path)) contains \"/wordpress\") or (lower(url_decode(http.request.uri.path)) contains \"/xmlrpc\") or (lower(url_decode(http.request.uri.path)) contains \"/phpmyadmin\") or (lower(url_decode(http.request.uri.path)) contains \"/pma\") or (lower(url_decode(http.request.uri.path)) contains \"/admin\") or (lower(url_decode(http.request.uri.path)) contains \"/cgi-bin\") or (lower(url_decode(http.request.uri.path)) contains \"/actuator\") or (lower(url_decode(http.request.uri.path)) contains \"/solr\") or (lower(url_decode(http.request.uri.path)) contains \"/telescope\") or (lower(url_decode(http.request.uri.path)) contains \"/vendor\") or (lower(url_decode(http.request.uri.path)) contains \"/invoker\") or (lower(url_decode(http.request.uri.path)) contains \"/balancer-manager\") or (lower(url_decode(http.request.uri.path)) contains \"/login\") or (lower(url_decode(http.request.uri.path)) contains \"/credentials\") or (lower(url_decode(http.request.uri.path)) contains \"/known_hosts\") or (lower(url_decode(http.request.uri.path)) contains \"sendgrid\") or (lower(url_decode(http.request.uri.path)) contains \"codecommit\") or (lower(url_decode(http.request.uri.path)) contains \"/env.cfg\") or (lower(url_decode(http.request.uri.path)) contains \"/api/config\") or (lower(url_decode(http.request.uri.path)) contains \"/careers_not_hosted\") or (lower(url_decode(http.request.uri.path)) contains \".php\") or (lower(url_decode(http.request.uri.path)) contains \".asp\") or (lower(url_decode(http.request.uri.path)) contains \".jsp\") or (lower(url_decode(http.request.uri.path)) contains \".cgi\") or (lower(url_decode(http.request.uri.path)) contains \".yml\") or (lower(url_decode(http.request.uri.path)) contains \".xml\") or (lower(url_decode(http.request.uri.path)) contains \".bak\") or (lower(url_decode(http.request.uri.path)) contains \".rb\") or (lower(url_decode(http.request.uri.path)) contains \".env.\")"
                  ref        : "block_scan_probes"
              }
      ]
Resources:
  ~ 3 to update
  13 unchanged
  

@andymeierdev andymeierdev force-pushed the andymeierdev/MEIER-352/fix-waf-case-bypass-and-otel-logs branch from d0b332e to b3f9ed7 Compare March 24, 2026 23:19
@andymeierdev andymeierdev merged commit c32e78a into main Mar 24, 2026
2 checks passed
@andymeierdev andymeierdev deleted the andymeierdev/MEIER-352/fix-waf-case-bypass-and-otel-logs branch March 24, 2026 23:28
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.

1 participant