Hugo v0.166.0 drops module mounts whose root, or any directory between
it and the project root, is a symlink. The isolated pnpm linker installs
every package as a symlink into `node_modules/.pnpm`, so all of the
Thulite, Tabler, Docsearch, and bootstrap-icons mounts disappear and the
build fails with `template for shortcode "callout" not found`. Switch
`docs` to the hoisted linker so packages are real directories, and
exclude `node_modules` from golangci-lint since the hoisted layout
exposes the Go sources shipped in `flatted`.
Migrate the deprecated configuration and template usage: `languageCode`
to `locale`, `languageName` to `label`, the global `imaging.quality` and
`imaging.hint` to the per format `avif`, `jpeg`, and `webp` settings,
and `.Language.LanguageName` to `.Language.Label`. The rendered site is
byte identical to the previous configuration on both v0.165.0 and
v0.166.0 apart from processed image file names.
Add docs suite tests asserting every `node_modules` mount resolves,
since a dropped mount does not always fail the build, and that the
locale and label still drive the document language and the English
homepage sections.
Signed-off-by: Amir Zarrinkafsh <3339418+nightah@users.noreply.github.com>
The import convention is four groups: the standard library, general
third party packages, the company packages under `authelia.com` and
`github.com/authelia`, and the project itself. `goimports` cannot
express this because `local-prefixes` describes a single trailing group
no matter how many prefixes are listed, so it tolerates the existing
layout but merges the company group into the third party group whenever
it formats a file, which `goimports-reviser` then has to undo.
`gci` is enabled to enforce it as its sections accept an ordered list,
with `prefix` covering both company prefixes and `localmodule` resolving
the project. It is bundled with `golangci-lint` so it replaces a
separately installed binary, and it runs after `goimports` so the two no
longer disagree about the result.
Equivalence was established by scrambling the import block of all six
hundred and thirteen files which have one and formatting the result with
each tool: the output is byte identical, including the twenty six
generated files both correctly decline to touch. `goimports-reviser` is
therefore removed from the reviewdog runners, the lint step, the git
hooks and the contributor documentation.
Signed-off-by: Amir Zarrinkafsh <3339418+nightah@users.noreply.github.com>
Exported symbols are documented inconsistently and nothing enforces it.
`revive` ships an `exported` rule which would cover part of this,
however the `revive` settings only specify `confidence` and declare no
rules, and golangci-lint v2 runs no `revive` rules at all unless they
are listed, so the gap went unnoticed. `godoclint` is enabled in
preference to configuring `revive` because its rules are individually
selectable, which allows requiring documentation without also adopting
the naming and stuttering checks.
The `require-doc`, `require-pkg-doc` and `require-stdlib-doclink` rules
are enabled alongside the default set and `no-unused-link`. `max-len`
remains disabled as its 77 character default conflicts with the
documentation already in the tree. Test files are excluded because
golangci-lint forces `require-doc` to include them regardless of the
linter configuration, which would otherwise require documentation for
every exported test helper.
This documents 681 exported symbols, adds a package comment to the 34
packages which lack one, and converts 131 plain text references to
standard library identifiers into doc links. Packages of more than one
file carry their comment in `doc.go` following the existing
`experimental/embed/doc.go`, and the single file command packages carry
it above `package main`.
`mockgen` is invoked with `-write_package_comment=false` as the package
comment it writes into the generated mocks is a second package comment
for `internal/authentication` and `internal/notification`. golangci-lint
applies `single-pkg-doc` to test files even though `require-doc` skips
them, so the generated comment cannot satisfy the requirement but does
conflict with the comment which does.
The JSON schemas are regenerated as `authelia-gen` sources the
descriptions of the `internal/configuration/schema` types from their
comments.
Additionally `issues.exclude-dirs` is replaced with
`linters.exclusions.paths` as the former is not part of the version 2
configuration schema. It was silently ignored, so `internal/mocks` was
never excluded and `golangci-lint config verify` failed.
Documenting `ValidateExtra` exposed an inconsistency in it. A single
valued extra attribute whose value has a known type that isn't the
configured type is rejected, however the equivalent multi valued case
fell through the type switch and returned no error, so an `integer`
attribute holding strings validated successfully. The multi valued
branch now returns an error in the same way the single valued branch
does. A regression test covers a multi valued attribute holding strings
against an `integer` `value_type` alongside the existing compatible
cases.
Signed-off-by: Amir Zarrinkafsh <3339418+nightah@users.noreply.github.com>
This PR contains the following updates:
| Package | Change |
[Age](https://docs.renovatebot.com/merge-confidence/) |
[Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [qs](https://redirect.github.com/ljharb/qs) | [`6.14.1` →
`6.14.2`](https://renovatebot.com/diffs/npm/qs/6.14.1/6.14.2) |

|

|
### GitHub Vulnerability Alerts
####
[CVE-2026-2391](https://redirect.github.com/ljharb/qs/security/advisories/GHSA-w7fw-mjwx-w883)
### Summary
The `arrayLimit` option in qs does not enforce limits for
comma-separated values when `comma: true` is enabled, allowing attackers
to cause denial-of-service via memory exhaustion. This is a bypass of
the array limit enforcement, similar to the bracket notation bypass
addressed in GHSA-6rw7-vpxm-498p (CVE-2025-15284).
### Details
When the `comma` option is set to `true` (not the default, but
configurable in applications), qs allows parsing comma-separated strings
as arrays (e.g., `?param=a,b,c` becomes `['a', 'b', 'c']`). However, the
limit check for `arrayLimit` (default: 20) and the optional
throwOnLimitExceeded occur after the comma-handling logic in
`parseArrayValue`, enabling a bypass. This permits creation of
arbitrarily large arrays from a single parameter, leading to excessive
memory allocation.
**Vulnerable code** (lib/parse.js: lines ~40-50):
```js
if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
return val.split(',');
}
if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
}
return val;
```
The `split(',')` returns the array immediately, skipping the subsequent
limit check. Downstream merging via `utils.combine` does not prevent
allocation, even if it marks overflows for sparse arrays.This
discrepancy allows attackers to send a single parameter with millions of
commas (e.g., `?param=,,,,,,,,...`), allocating massive arrays in memory
without triggering limits. It bypasses the intent of `arrayLimit`, which
is enforced correctly for indexed (`a[0]=`) and bracket (`a[]=`)
notations (the latter fixed in v6.14.1 per GHSA-6rw7-vpxm-498p).
### PoC
**Test 1 - Basic bypass:**
```
npm install qs
```
```js
const qs = require('qs');
const payload = 'a=' + ','.repeat(25); // 26 elements after split (bypasses arrayLimit: 5)
const options = { comma: true, arrayLimit: 5, throwOnLimitExceeded: true };
try {
const result = qs.parse(payload, options);
console.log(result.a.length); // Outputs: 26 (bypass successful)
} catch (e) {
console.log('Limit enforced:', e.message); // Not thrown
}
```
**Configuration:**
- `comma: true`
- `arrayLimit: 5`
- `throwOnLimitExceeded: true`
Expected: Throws "Array limit exceeded" error.
Actual: Parses successfully, creating an array of length 26.
### Impact
Denial of Service (DoS) via memory exhaustion.
### Suggested Fix
Move the `arrayLimit` check before the comma split in `parseArrayValue`,
and enforce it on the resulting array length. Use `currentArrayLength`
(already calculated upstream) for consistency with bracket notation
fixes.
**Current code** (lib/parse.js: lines ~40-50):
```js
if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
return val.split(',');
}
if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
}
return val;
```
**Fixed code:**
```js
if (val && typeof val === 'string' && options.comma && val.indexOf(',') > -1) {
const splitArray = val.split(',');
if (splitArray.length > options.arrayLimit - currentArrayLength) { // Check against remaining limit
if (options.throwOnLimitExceeded) {
throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
} else {
// Optionally convert to object or truncate, per README
return splitArray.slice(0, options.arrayLimit - currentArrayLength);
}
}
return splitArray;
}
if (options.throwOnLimitExceeded && currentArrayLength >= options.arrayLimit) {
throw new RangeError('Array limit exceeded. Only ' + options.arrayLimit + ' element' + (options.arrayLimit === 1 ? '' : 's') + ' allowed in an array.');
}
return val;
```
This aligns behavior with indexed and bracket notations, reuses
`currentArrayLength`, and respects `throwOnLimitExceeded`. Update README
to note the consistent enforcement.
---
### Release Notes
<details>
<summary>ljharb/qs (qs)</summary>
###
[`v6.14.2`](https://redirect.github.com/ljharb/qs/blob/HEAD/CHANGELOG.md#6142)
[Compare
Source](https://redirect.github.com/ljharb/qs/compare/v6.14.1...v6.14.2)
- \[Fix] `parse`: mark overflow objects for indexed notation exceeding
`arrayLimit`
([#​546](https://redirect.github.com/ljharb/qs/issues/546))
- \[Fix] `arrayLimit` means max count, not max index, in
`combine`/`merge`/`parseArrayValue`
- \[Fix] `parse`: throw on `arrayLimit` exceeded with indexed notation
when `throwOnLimitExceeded` is true
([#​529](https://redirect.github.com/ljharb/qs/issues/529))
- \[Fix] `parse`: enforce `arrayLimit` on `comma`-parsed values
- \[Fix] `parse`: fix error message to reflect arrayLimit as max index;
remove extraneous comments
([#​545](https://redirect.github.com/ljharb/qs/issues/545))
- \[Robustness] avoid `.push`, use `void`
- \[readme] document that `addQueryPrefix` does not add `?` to empty
output ([#​418](https://redirect.github.com/ljharb/qs/issues/418))
- \[readme] clarify `parseArrays` and `arrayLimit` documentation
([#​543](https://redirect.github.com/ljharb/qs/issues/543))
- \[readme] replace runkit CI badge with shields.io check-runs badge
- \[meta] fix changelog typo (`arrayLength` → `arrayLimit`)
- \[actions] fix rebase workflow permissions
</details>
---
### Configuration
📅 **Schedule**: Branch creation - "" (UTC), Automerge - At any time (no
schedule defined).
🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box
---
This PR was generated by [Mend Renovate](https://mend.io/renovate/).
View the [repository job
log](https://developer.mend.io/github/authelia/authelia).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My44LjUiLCJ1cGRhdGVkSW5WZXIiOiI0My44LjUiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOlsiZGVwZW5kZW5jaWVzIiwiamF2YXNjcmlwdCJdfQ==-->
---------
Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: James Elliott <james-d-elliott@users.noreply.github.com>
This change implements yamllint and adjusts all yaml files to abide by our linting setup. This excludes config.template.yml as this will be done in an alternate commit.
* ci: publish docker images to ghcr
* ci: remove ghcr images with no tags
* ci: remove unnecessary ghcr jq args for empty tags
* ci: move ghcr empty tag clean up
Publishes Docker container images on both DockerHub and GitHub Container Registry.