Skip to content

fix(ssl): keep the HTTP-01 challenge files readable under a strict umask - #516

Merged
mrrobot47 merged 1 commit into
EasyEngine:developfrom
mrrobot47:fix/acme-challenge-permissions
Oct 12, 2026
Merged

mrrobot47 merged 1 commit into
EasyEngine:developfrom
mrrobot47:fix/acme-challenge-permissions

Conversation

@mrrobot47

Copy link
Copy Markdown
Member

Under a strict umask (for example 077) the HTTP-01 challenge directory and token were created unreadable for nginx, so Let's Encrypt validation failed with "Can not validate challenge".

  • authorize() sets .well-known and acme-challenge to 0755, and the token and vhost.d/default to 0644, whatever the umask. The token is chmod-ed after it is written, because an existing file keeps its mode.
  • A new prepare_http_challenge_dir() creates or repairs the directory and the modes of token files already in it. A link or file at .well-known or acme-challenge is removed instead of being chmod-ed through, and links inside the token directory are left alone.
  • check() repairs the directory too, so ee site ssl-verify of a pending order heals a directory left unreadable by an older version. Stale tokens are kept, so retries of pending orders still validate.
  • The www check removes whatever is at check.html and creates the file exclusively with a 022 umask, so it is readable and never written through an existing file or link.

Tested with PHPUnit and a harness that drives the real authorize(), check() and the www check under umask 077 and 022 on PHP 7.4 and 8.5, and live with real HTTP-01 issuances under umask 077.

Under umask 077 or 027 the challenge dir .well-known/acme-challenge came out 0700 and the token, vhost.d/default and the www check.html 0600, so nginx-proxy and the site's nginx couldn't read them: the local challenge self-check failed with "Can not validate challenge" and the www check got a 403. cleanup() only runs after a successful verify, so the 0700 dir stayed behind and broke every later HTTP-01 attempt, even at umask 022.

authorize() now sets 0755 on .well-known and acme-challenge and 0644 on the token and vhost.d/default whatever the umask, and repairs an existing challenge dir and its token files. check() repairs it as well, since ssl-verify retries a pending order against the token already on disk without calling authorize(). Stale tokens are kept for that reason. A symlink or file at .well-known or acme-challenge is removed instead of being chmod-ed through, and links in the token dir are left alone.

The www check removes whatever is at check.html (the site can write to its webroot) and creates the file exclusively under umask 022, so a planted symlink is no longer followed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The permission repairs and symlink protections correctly address strict-umask failures without identified regressions.

0 open findings

What changed in this PR

Ensures HTTP-01 validation files remain nginx-readable under restrictive umasks.

Changes:

  • Repairs challenge-directory and token permissions safely.
  • Creates the www-check file exclusively with readable permissions.
File Description
src/​helper/​Site_Letsencrypt.php Repairs HTTP-01 paths and permissions.
src/​helper/​class-ee-site.php Safely creates the domain-check file.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@mrrobot47
mrrobot47 merged commit b67eea8 into EasyEngine:develop Oct 12, 2026
3 checks passed
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.

2 participants