bakkesmod-legendary

maintainer kentslaney · 0 votes · scanned 2026-08-03 00:08:14.047287
LOW
View on AUR ↗
Why flagged The package builds from official and maintainer-owned GitHub sources, with only one SKIP'd checksum for a small loopback component; the eval usage is limited to conditional execution of known PowerShell paths and does not involve untrusted remote code execution.

Triggered rules

LOW AI review downgraded a static finding llm_review

The static rules flagged this MEDIUM, but an AI model (qwen/qwen3-235b-a22b-07-25) reviewed the full PKGBUILD and judged it LOW (confidence 95%): The package builds from official and maintainer-owned GitHub sources, with only one SKIP'd checksum for a small loopback component; the eval usage is limited to conditional execution of known PowerShell paths and does not involve untrusted remote code execution.

  • PKGBUILD:283 WINEFSYNC=1 WINEPREFIX="$pfx" eval "$wine_bin launching &"
1 higher static finding superseded - not the current verdict (shown for transparency)
MEDIUM source=() URL on a non-standard host source_untrusted_domain

One or more source=() URLs point to a host outside the trusted allowlist (github.com, gitlab.com, codeberg.org, pypi.org, …).

  • PKGBUILD:35 "https://www.7-zip.org/a/7z2501-x64.exe"

PKGBUILD

2 offending line(s) highlighted
1# Maintainer: Kent Slaney <kent@slaney.org>
2pkgname=bakkesmod-legendary
3rlver=( 2 0 71 )
4pkgver="${rlver[0]}.${rlver[2]}"
5pkgrel=1
6pkgdesc="A mod aimed at making you better at Rocket League!"
7arch=('x86_64')
8url="https://bakkesmod.com/"
9license=('GPL')
10groups=()
11depends=()
12makedepends=('python' 'jq')
13optdepends=()
14
15# versionless URLs and official repo backups
16# "https://github.com/bakkesmodorg/BakkesModInjectorCpp/releases/latest/download/BakkesModSetup.exe"
17# "https://github.com/bakkesmodorg/BakkesModInjectorCpp/releases/latest/download/BakkesModInjectorWin7.zip"
18# "https://github.com/bakkesmodorg/BakkesModInjectorCpp/releases/latest/download/BakkesMod.zip"
19# "https://api.github.com/repos/bakkesmodorg/BakkesModInjectorCpp/zipball/master"
20
21rlstr=$(IFS=. ; echo "${rlver[*]}")
22rlesc=$(IFS=- ; echo "${rlver[*]}")
23pkgesc=`echo "$pkgver" | sed 's%\.%-%g'`
24
25source=(
26 "dll-$rlesc.zip::https://github.com/bakkesmodorg/BakkesModInjectorCpp/releases/download/$rlstr/bakkesmod.zip"
27 "src-$rlesc.zip::https://github.com/bakkesmodorg/BakkesModInjectorCpp/archive/refs/tags/$rlstr.zip"
28 "loopback-$pkgesc-$pkgrel.zip::https://github.com/kentslaney/bakkesmod-arch/archive/refs/tags/$pkgver-$pkgrel-legendary.zip"
29 "https://github.com/kentslaney/bakkesmod-arch/releases/download/c369f24-1/inject.exe"
30
31 "https://github.com/kentslaney/bakkesmod-arch/releases/download/05ea332-1/powershell32.exe"
32 "https://github.com/kentslaney/bakkesmod-arch/releases/download/05ea332-1/powershell64.exe"
33 "https://github.com/PowerShell/PowerShell/releases/download/v7.4.1/PowerShell-7.4.1-win-x64.msi"
34 "https://github.com/Maximus5/ConEmu/releases/download/v23.07.24/ConEmuPack.230724.7z"
35 "https://www.7-zip.org/a/7z2501-x64.exe"
36 "https://raw.githubusercontent.com/PietJankbal/powershell-wrapper-for-wine/master/profile.ps1"
37)
38
39sha256sums=(
40 'db8b62a026faafb08b5838c712898bc2ab81817e8b1bfa416091440b2ff958d0'
41 'e49929c27a91610262e4d9ea3bb39e481effe983d4671ed06d349f523c1a6180'
42 'SKIP'
43 '0e038a4f0a2799f6aaa34f6560f5d1d41fba0cf26f8814571cebc94f5bb67a6e'
44
45 '196886b557e632547d32354f20834e88ba3726df29a486c85d6409900064f364'
46 'e8dae4079a66d5a1564c577bd27caf8c890a1044d9c56948581591e196e4ac8c'
47 '66c7c35ed9a46bd27e3d915dcf9a05e38b3f5ebb039883b92aa62ffea20fb187'
48 '2a9b98ebecaede62665ef427b05b3a5ccdac7bd3202414fc0f4c10825b4f4ea2'
49 '78afa2a1c773caf3cf7edf62f857d2a8a5da55fb0fff5da416074c0d28b2b55f'
50 'b0fd5df54a2b281348ab03c2942b1e83278bee62c71e06d3d671724b49946593'
51)
52
53build() {
54 # folder with official injector release (commit hash in name)
55 ref=`find "$srcdir" -maxdepth 1 -name "*Cpp-$rlstr" -type d`
56 # move loopback src to srcdir
57 tmp=$(mktemp -d)
58 unzip -qd "$tmp" "$srcdir/loopback-$pkgesc-$pkgrel.zip"
59 mv "$tmp"/*/* "$srcdir"
60 rm -fr "$tmp"/* "$tmp"
61 rm -rf "$srcdir/7zr.exe" && cp "$srcdir"/7z*-x64.exe "$srcdir/7zr.exe"
62}
63
64compile() {
65 # MinGW and VS header disagreement
66 patches="$srcdir/include"
67 mkdir -p "$patches"
68 ln -sf /usr/x86_64-w64-mingw32/include/windows.h "$patches/Windows.h"
69 ln -sf /usr/x86_64-w64-mingw32/include/sdkddkver.h "$patches/SDKDDKVer.h"
70 ln -sf /usr/x86_64-w64-mingw32/include/shlobj.h "$patches/shlobj_core.h"
71 ln -sf "$ref/BakkesModWPF/Resource.h" "$patches/resource.h"
72
73 # has to be below C++20 which removes ofstream functionality
74 CXX_FLAGS=( "-std=c++17" "-static-libgcc" "-static-libstdc++" "-static" "-municode" "-mconsole" "-lpsapi" "-w" )
75 CXX_LD=( "-I$patches" "-I/usr/x86_64-w64-mingw32/include" "-I$ref/BakkesModInjectorC++" )
76
77 # std::search is defined in std::algorithm
78 includes="#include <algorithm>"
79 sed "s%pragma once%pragma once\n$includes%" \
80 "$ref/BakkesModInjectorC++/WindowsUtils.h" > "$patches/WindowsUtils.h"
81 ln -sf "$patches/WindowsUtils.h" "$patches/windowsutils.h"
82
83 # unused, faster and easier to short circuit
84 getter="WindowsUtils::GetMyDocumentsFolder()"
85 docs='C:\\\\users\\\\steamuser\\\\Documents'
86 sed -z "s%$getter[^{]*{%$getter { return \"$docs\";%" \
87 "$ref/BakkesModInjectorC++/WindowsUtils.cpp" > "$patches/WindowsUtils.cpp"
88
89 wpath="s%std::filesystem::path path%const wchar_t* path%g"
90 sed "s%path.wstring().c_str()%path%" \
91 "$ref/BakkesModInjectorC++/DllInjector.cpp" > "$patches/DllInjector.cpp"
92 sed -i "$wpath" "$patches/DllInjector.cpp"
93 sed "$wpath" "$ref/BakkesModInjectorC++/DllInjector.h" > "$patches/DllInjector.h"
94 x86_64-w64-mingw32-g++ "${CXX_FLAGS[@]}" "${CXX_LD[@]}" \
95 "$patches/WindowsUtils.cpp" \
96 "$ref/BakkesModWPF/BakkesModWPF.cpp" \
97 "$patches/DllInjector.cpp" \
98 "$srcdir/main.cpp" -o "$srcdir/inject.exe"
99}
100
101legendary_prefixes=(
102 "$LEGENDARY_CONFIG_PATH"
103 "$HOME/.config/legendary"
104 "$HOME/.var/app/com.heroicgameslauncher.hgl/config/legendary"
105 "$HOME/.config/heroic/legendaryConfig/legendary"
106 "$HOME/.var/app/com.heroicgameslauncher.hgl/config/heroic/legendaryConfig/legendary"
107)
108heroic_prefixes=(
109 "$HOME/.config/heroic/GamesConfig/Sugar.json"
110 "$HOME/.var/app/com.heroicgameslauncher.hgl/config/heroic/GamesConfig/Sugar.json"
111)
112heroic_global=(
113 "$HOME/.config/heroic/config.json"
114 "$HOME/.var/app/com.heroicgameslauncher.hgl/config/heroic/config.json"
115)
116wine_bm_path="drive_c/users/steamuser/AppData/Roaming/bakkesmod"
117
118installed_version() {
119 jq -er .Sugar.version < "$1"
120}
121
122install_data() {
123 for fp in "${legendary_prefixes[@]}"; do
124 installed="$fp/installed.json"
125 if [ -f "$installed" ] && ( installed_version "$installed" > /dev/null ); then
126 echo "$installed"
127 return 0
128 fi
129 done
130 echo "could not find a LEGENDARY_CONFIG_PATH with Rocket League installed" >&2
131 echo "if on SteamOS, re-run from the deck account" >&2
132 exit 1
133}
134
135wine_pfx() {
136 pfx=`jq -er .Sugar.install_path < "$1"`
137 echo "$(dirname "$pfx")/Prefixes/default/Rocket League"
138}
139
140heroic_env() {
141 for fp in "${heroic_prefixes[@]}"; do
142 if [ -f "$fp" ]; then
143 echo "$fp"
144 return 0
145 fi
146 done
147}
148
149heroic_config() {
150 for fp in "${heroic_global[@]}"; do
151 if [ -f "$fp" ]; then
152 jq -er .defaultSettings.defaultSteamPath < "$fp"
153 return 0
154 fi
155 done
156}
157
158build_version() {
159 RL_version="$(installed_version "$1")"
160 echo "$RL_version.$( cat "$srcdir/version.txt" ).$pkgver.$pkgrel"
161}
162
163powershell_installer() {
164 eval "$1 'C:\windows\system32\WindowsPowerShell\v1.0\powershell.exe' -noni -c 'echo \"powershell64_installed\"'"
165 eval "$1 'C:\windows\syswow64\WindowsPowerShell\v1.0\powershell.exe' -noni -c 'echo \"powershell32_installed\"'"
166}
167
168powershell() {
169 rm -f fsync
170 python sandbox.py > fsync &
171 sandbox_pid=$!
172 trap "if kill -0 '$sandbox_pid' &> /dev/null; then kill '$sandbox_pid'; fi" EXIT
173 echo -n "waiting for sandbox port "
174 tail -f fsync | grep -m 1 "."
175
176 pth32="$WINEPREFIX/drive_c/windows/system32/WindowsPowerShell/v1.0/powershell.exe"
177 pth64="$WINEPREFIX/drive_c/windows/syswow64/WindowsPowerShell/v1.0/powershell.exe"
178
179 cp -f powershell32_.exe "$pth32"; cp -f powershell64_.exe "$pth64";
180 ( powershell_installer "$1" 2>pwsh.log ) || ( cat pwsh.log && false )
181 cp -f powershell32.exe "$pth32"; cp -f powershell64.exe "$pth64";
182 if kill -0 "$sandbox_pid" &> /dev/null; then kill "$sandbox_pid"; fi
183 rm -f fsync
184}
185
186package() {
187 installed=`install_data`
188 echo "build version string: $(build_version "$installed")"
189
190 pfx=`wine_pfx "$installed"`
191 pfx0="$pfx"
192 if ! [ -a "$pfx/user.reg" ]; then pfx="$pfx/pfx"; fi # proton specific (?)
193 user=`grep '^"USERNAME"="' "$pfx/user.reg" | sed "s/^[^=]*=\"\|\"$//g"`
194 # creates broken (ignored) symlink if $user == "steamuser"
195 ( cd "$pfx/drive_c/users" && ln -sf "$user" "steamuser" )
196
197 bm_pfx="$pfx/$wine_bm_path"
198 mkdir -p "$bm_pfx"
199 py=$(sed "s/^ \{8\}//" <<" EOF"
200 import os, pathlib, sys
201 f, pfx, env = (pathlib.Path(os.environ[i]) for i in ("FP", "PFX", "SUGAR_ENV"))
202
203 # legendary launch command
204 import configparser, shlex
205 cfg = configparser.ConfigParser()
206 cfg.read(f)
207 if not cfg.has_section("Sugar"):
208 cfg.add_section("Sugar")
209 cmd = shlex.join(("sh", str(pfx / "runner.sh")))
210 cfg["Sugar"]["pre_launch_command"] = cmd
211 cfg["Sugar"]["pre_launch_wait"] = "true"
212 with open(f, "w") as fp:
213 cfg.write(fp)
214
215 # heroic env variables
216 import json
217 if not env.is_file():
218 print("wine")
219 exit(0)
220 with open(env) as fp:
221 opt = json.load(fp)
222 environ = opt.get("Sugar", {}).get("enviromentOptions", [])
223 opt["Sugar"] = {**opt.get("Sugar", {}), "enviromentOptions": environ}
224 preset = [i["key"] for i in environ]
225 changed = False
226 for var in ("BAKKES", "PROMPTLESS"):
227 if var not in preset:
228 changed = True
229 environ.append({"key": var, "value": "1"})
230 else:
231 last = len(preset) - 1 - list(reversed(preset)).index(var)
232 initial = environ[last]["value"]
233 if initial != "1":
234 print(f"warning: Heroic flag {var} is set to {initial}", file=sys.stderr)
235 if changed:
236 with open(env, "w") as fp:
237 json.dump(opt, fp, indent=2)
238 try:
239 cmd = [opt["Sugar"]["wineVersion"]["bin"]]
240 if opt["Sugar"]["wineVersion"]["type"] == "proton":
241 cmd.append("run")
242 print(shlex.join(cmd))
243 except:
244 print("wine")
245 EOF
246 )
247 cfg="$(dirname "$installed")/config.ini"
248 wine_bin=`PFX="$bm_pfx" FP="$cfg" SUGAR_ENV="$(heroic_env)" python -c "$py"`
249
250 sed "s/^ \{8\}//" <<" EOF" > "$bm_pfx/runner.py"
251 import argparse, os, shlex, pathlib
252
253 with open("/proc/{}/cmdline".format(os.environ["PS"])) as fp:
254 cmd = fp.read().rstrip("\x00").split("\x00")
255 parser = argparse.ArgumentParser()
256 parser.add_argument("--wine", action="append", default=[])
257 parser.add_argument("--wrapper", default=[])
258 flags, _ = parser.parse_known_args(cmd)
259 flags.wrapper = flags.wrapper and shlex.split(flags.wrapper)
260 pfx = pathlib.Path(__file__).parents[0]
261
262 def wrap(wrapper):
263 proton = os.environ.get("PROTONPATH", "")
264 if len(flags.wrapper) < 2 or not proton:
265 return wrapper
266 relative = pathlib.Path(flags.wrapper[0]).relative_to(pathlib.Path(proton))
267 if relative != pathlib.Path('proton'):
268 return wrapper
269 return [str(proton / pathlib.Path("files/bin/wine64"))]
270
271 print(shlex.join(wrap(flags.wrapper) + flags.wine + [str(pfx / "inject.exe")]))
272 EOF
273
274 json_pfx=`jq -e .Sugar.install_path < "$installed"`
275 echo "pfx=$json_pfx" > "$bm_pfx/runner.sh"
276 cat <<" EOF" >> "$bm_pfx/runner.sh"
277 pfx="$(dirname "$pfx")/Prefixes/default/Rocket League"
278 bm_pfx=`dirname "$0"`
279 wine_bin=`PS="$PPID" python "$bm_pfx/runner.py"`
280 if [ "$BAKKES" != 1 ]; then exit 0; fi
281 dll=`[ "$PROMPTLESS" = 1 ] && echo "bakkesmod_promptless.dll" || echo "bakkesmod_official.dll"`
282 ln -sf "$bm_pfx/bakkesmod/dll/$dll" "$bm_pfx/bakkesmod/dll/bakkesmod.dll"
283 WINEFSYNC=1 WINEPREFIX="$pfx" eval "$wine_bin launching &"
284 EOF
285
286 dll_path="$bm_pfx/bakkesmod/dll"
287 rm -f "$dll_path/bakkesmod.dll"
288 unzip -quo "dll-$rlesc.zip" -d "$bm_pfx/bakkesmod"
289 # by default, starts with bakkesmod.dll and outputs bakkesmod_promptless.dll
290 echo -n "shunted winuser calls for DLL patch: "
291 python "$srcdir/dll_patch.py" "$dll_path"
292 mv "$dll_path/bakkesmod.dll" "$dll_path/bakkesmod_official.dll"
293 ln -sf "$dll_path/bakkesmod_official.dll" "$dll_path/bakkesmod.dll"
294
295 cp -f "$srcdir/inject.exe" "$bm_pfx"
296 if [ -f "$pfx/drive_c/Program Files/PowerShell/7/pwsh.exe" ]; then
297 echo "skipping powershell installation in favor of existing pwsh.exe"
298 else
299 ( cd "$srcdir" && LD_PRELOAD= WINEPREFIX="$pfx" STEAM_COMPAT_DATA_PATH="$pfx0" STEAM_COMPAT_CLIENT_INSTALL_PATH="$(heroic_config)" powershell "$wine_bin" )
300 fi
301}
302
303pre_remove() {
304 installed=`install_data`
305 pfx=`wine_pfx "$installed"`
306 bm_pfx="$pfx/$wine_bm_path"
307
308 py=$(sed "s/^ \{8\}//" <<" EOF"
309 import os, pathlib
310 f, pfx, env = (pathlib.Path(os.environ[i]) for i in ("FP", "PFX", "SUGAR_ENV"))
311
312 # legendary launch command
313 import configparser, shlex
314 cfg = configparser.ConfigParser()
315 cfg.read(f)
316 if cfg.has_section("Sugar"):
317 cmd = shlex.join(("sh", str(pfx / "runner.sh")))
318 if (
319 cfg["Sugar"].get("pre_launch_command").startswith(cmd) and
320 cfg["Sugar"].get("pre_launch_wait") == "true"):
321 cfg.remove_option("Sugar", "pre_launch_command")
322 cfg.remove_option("Sugar", "pre_launch_wait")
323 if len(cfg.options("Sugar")) == 0:
324 cfg.remove_section("Sugar")
325 with open(f, "w") as fp:
326 cfg.write(fp)
327
328 # heroic env variables
329 import json
330 if env.is_file():
331 with open(env) as fp:
332 opt = json.load(fp)
333 environ = opt["Sugar"]["enviromentOptions"]
334 preset = [i["key"] for i in environ]
335 changed = False
336 for var in ("BAKKES", "PROMPTLESS"):
337 if var in preset:
338 last = len(preset) - 1 - list(reversed(preset)).index(var)
339 if environ[last]["value"] == "1":
340 changed = True
341 environ.pop(last)
342 preset.pop(last)
343 if changed:
344 with open(env, "w") as fp:
345 json.dump(opt, fp, indent=2)
346 EOF
347 )
348 cfg="$(dirname "$installed")/config.ini"
349 PFX="$bm_pfx" FP="$cfg" SUGAR_ENV="$(heroic_env)" python -c "$py"
350
351 rm -fr "$bm_pfx"
352 linked="$pfx/drive_c/users/steamuser"
353 if [ -h "$linked" ]; then rm "$linked"
354 elif [ -d "$linked" ] && [ -h "$linked/steamuser" ]; then rm "$linked/steamuser"
355 fi
356}
357

Scan history

Scanned at (UTC)SeverityRules
2026-08-03 00:08:14 LOW 2
2026-08-02 00:16:08 LOW 2
2026-08-01 00:11:18 LOW 2
2026-07-31 00:14:10 LOW 2
2026-07-30 00:17:23 LOW 2
2026-07-29 00:25:53 LOW 2
2026-07-28 00:07:28 LOW 2
2026-07-27 00:24:32 LOW 2
2026-07-26 00:07:32 LOW 2
2026-07-25 00:13:44 LOW 2
2026-07-24 00:02:28 LOW 2
2026-07-23 00:14:47 LOW 2
2026-07-22 00:29:32 LOW 2
2026-07-21 00:24:15 LOW 2
2026-07-20 00:19:49 LOW 2
2026-07-19 00:17:08 LOW 2
2026-07-18 00:14:48 LOW 2
2026-07-17 00:06:16 LOW 2
2026-07-16 00:05:41 LOW 2
2026-07-15 00:09:25 LOW 2

Report a package

Reports go to the AURWatch maintainer (one person) and are read by hand. No login required.

0 / 4000
Your suggestion