Skip to content

Commit cecc90a

Browse files
committed
fix(ci): close three gaps found in CodeRabbit review of the AUR audit
- sha256sums pouvait devenir plus court que source=(). Une entrée locale et légitime (.install, .desktop) ne produit aucune URL ; on écrivait alors un tableau désaligné que makepkg génère sans broncher et que le contrôle de diff laisse passer, pour finir en échec de vérification chez chaque utilisateur. On compte les entrées et on refuse un formatage non reconnu. - Le test de préfixe de l'allowlist ne contraignait pas l'origine réellement contactée : curl normalise les segments .. avant la requête, donc .../getopenscreen/openscreen/../../attacker/repo/x passait et allait chercher le dépôt d'un tiers. Reproduit — l'URL effective devient bien github.com/attacker/repo. Segments .., pourcent, arobase et antislash refusés, et l'hôte d'arrivée est vérifié après redirection. - La liste de motifs du préambule ignorait la substitution de processus. 23 assertions passent, dont 15 négatives.
1 parent 5f13d8d commit cecc90a

1 file changed

Lines changed: 38 additions & 1 deletion

File tree

.github/workflows/aur-publish.yml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ jobs:
132132
done <<'PATTERNS'
133133
\$\(
134134
`
135+
[<>]\(
135136
(^|[;&|[:space:]])(eval|source|curl|wget|bash|sh|python3?)[[:space:]]
136137
PATTERNS
137138
@@ -204,6 +205,23 @@ jobs:
204205
exit 1
205206
fi
206207
208+
# sha256sums doit rester aligné sur source=(), élément par élément. Une
209+
# entrée locale et légitime (un .install, un .desktop) ne produit aucune
210+
# URL : on écrirait alors un tableau plus court, que makepkg accepte de
211+
# générer et que le contrôle de diff laisse passer — pour finir en échec
212+
# de vérification chez chaque utilisateur. On compte les entrées, et on
213+
# refuse tout formatage qu'on ne sait pas compter plutôt que de deviner.
214+
ENTRIES=$(grep -oE '"[^"]*"' <<<"$SRC_BLOCK" | wc -l)
215+
RESIDUE=$(sed -e 's/"[^"]*"//g' <<<"$SRC_BLOCK" | tr -d '[:space:]')
216+
if [[ "$RESIDUE" != "source=()" ]]; then
217+
echo "::error::source=() holds unquoted entries; refusing to guess its shape"
218+
exit 1
219+
fi
220+
if [[ "${#URLS[@]}" -ne "$ENTRIES" ]]; then
221+
echo "::error::source=() holds ${ENTRIES} entries but ${#URLS[@]} are URLs; sha256sums would not align"
222+
exit 1
223+
fi
224+
207225
SUMS=()
208226
for url in "${URLS[@]}"; do
209227
# Allowlist : une source pointant ailleurs que sur notre dépôt signifie
@@ -213,8 +231,27 @@ jobs:
213231
echo "::error::Expected everything under ${ALLOWED_SOURCE_PREFIX}"
214232
exit 1
215233
fi
234+
# Le test de préfixe seul ne suffit pas : curl normalise les segments
235+
# `..` AVANT d'émettre la requête, donc
236+
# .../getopenscreen/openscreen/../../attacker/repo/x passe le préfixe
237+
# et va chercher le dépôt d'un tiers. Vérifié : l'URL effective
238+
# devient bien https://github.com/attacker/repo/x. Le pourcent est
239+
# refusé au passage, %2e%2e n'étant normalisé que côté serveur.
240+
if [[ "$url" == *".."* || "$url" == *"%"* || "$url" == *"@"* || "$url" == *'\'* ]]; then
241+
echo "::error::Source URL contains path traversal, encoding or userinfo: $url"
242+
exit 1
243+
fi
216244
echo "Fetching $url"
217-
curl -fsSL --retry 3 -o /tmp/src.bin "$url"
245+
# -L reste nécessaire (les assets de release redirigent vers le CDN),
246+
# donc on contrôle l'hôte d'arrivée plutôt que d'interdire le saut.
247+
EFFECTIVE=$(curl -fsSL --retry 3 --proto '=https' \
248+
-w '%{url_effective}' -o /tmp/src.bin "$url")
249+
EFF_HOST=${EFFECTIVE#https://}
250+
EFF_HOST=${EFF_HOST%%/*}
251+
if [[ "$EFF_HOST" != "github.com" && "$EFF_HOST" != *".githubusercontent.com" ]]; then
252+
echo "::error::Download redirected off GitHub: $EFFECTIVE"
253+
exit 1
254+
fi
218255
SUMS+=("$(sha256sum /tmp/src.bin | awk '{print $1}')")
219256
done
220257

0 commit comments

Comments
 (0)