Fix open redirect in tag.php + language.php: reject protocol-relative URLs (//evil.com) by also checking for // prefix

This commit is contained in:
Pontoporeia
2026-06-24 14:15:14 +02:00
parent 6ecd3d4540
commit 84869ad968
3 changed files with 13 additions and 7 deletions

View File

@@ -1,9 +1,10 @@
# TODO # TODO
> Last updated: 2026-06-24 > Last updated: 2026-06-24
> Context: Setup biome + rolldown + lightningcss build pipeline for JS/CSS bundling & minification > Context: Security audit — fix open redirects, fragment auth, dead code, CSRF gaps
## Completed ## Completed
- [x] #sec-open-redirect Fix open redirect in tag.php + language.php (protocol-relative URL bypass via str_starts_with) ✓
- [x] #build-pipeline Setup biome + rolldown + lightningcss build pipeline ✓ - [x] #build-pipeline Setup biome + rolldown + lightningcss build pipeline ✓
- [x] #build-packagejson Create package.json with devDependencies ✓ - [x] #build-packagejson Create package.json with devDependencies ✓
- [x] #build-biomecss Update biome.json to handle CSS formatting ✓ - [x] #build-biomecss Update biome.json to handle CSS formatting ✓
@@ -15,6 +16,9 @@
- [x] #build-cssfix Fix stray `}` syntax error in admin.css line 305 ✓ - [x] #build-cssfix Fix stray `}` syntax error in admin.css line 305 ✓
## Pending ## Pending
- [ ] #sec-fragments-auth Gate partagé fragments on share_active session + CSRF `(partage/fragments/*.php, partage/index.php)`
- [ ] #sec-retry-csrf Add CSRF check to partage/retry-email.php POST
- [ ] #sec-cleanup-dead-code Remove dead App::verifyCsrf() or refactor action handlers to use it
- [ ] #rep-student-touch Replace hover student popover with tap-to-open drawer for mobile `(repertoire.php, repertoire.css)` - [ ] #rep-student-touch Replace hover student popover with tap-to-open drawer for mobile `(repertoire.php, repertoire.css)`
- [ ] #rep-polish Polish: scroll-position memory on HTMX swap, animation tuning `(repertoire.css)` - [ ] #rep-polish Polish: scroll-position memory on HTMX swap, animation tuning `(repertoire.css)`
- [ ] #icon-color-verify Verify icon colors render correctly across all pages (header, admin tables, forms, dialogs, cleanup modal) - [ ] #icon-color-verify Verify icon colors render correctly across all pages (header, admin tables, forms, dialogs, cleanup modal)

View File

@@ -74,9 +74,10 @@ try {
} }
$redirect = '/admin/contenus.php'; $redirect = '/admin/contenus.php';
// Allow the caller to override the redirect // Allow the caller to override the redirect (same-origin only, no protocol-relative)
if (!empty($_POST['return']) && str_starts_with($_POST['return'], '/')) { $return = $_POST['return'] ?? '';
$redirect = $_POST['return']; if ($return !== '' && str_starts_with($return, '/') && !str_starts_with($return, '//')) {
$redirect = $return;
} }
header('Location: ' . $redirect); header('Location: ' . $redirect);
exit(); exit();

View File

@@ -79,9 +79,10 @@ try {
} }
$redirect = '/admin/tags.php'; $redirect = '/admin/tags.php';
// Allow the caller to override the redirect // Allow the caller to override the redirect (same-origin only, no protocol-relative)
if (!empty($_POST['return']) && str_starts_with($_POST['return'], '/')) { $return = $_POST['return'] ?? '';
$redirect = $_POST['return']; if ($return !== '' && str_starts_with($return, '/') && !str_starts_with($return, '//')) {
$redirect = $return;
} }
header('Location: ' . $redirect); header('Location: ' . $redirect);
exit(); exit();