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>
2
pkgname=bakkesmod-legendary
3
rlver=( 2 0 71 )
4
pkgver="${rlver[0]}.${rlver[2]}"
5
pkgrel=1
6
pkgdesc="A mod aimed at making you better at Rocket League!"
7
arch=('x86_64')
8
url="https://bakkesmod.com/"
9
license=('GPL')
10
groups=()
11
depends=()
12
makedepends=('python' 'jq')
13
optdepends=()
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
21
rlstr=$(IFS=. ; echo "${rlver[*]}")
22
rlesc=$(IFS=- ; echo "${rlver[*]}")
23
pkgesc=`echo "$pkgver" | sed 's%\.%-%g'`
24
25
source=(
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
39
sha256sums=(
40
'db8b62a026faafb08b5838c712898bc2ab81817e8b1bfa416091440b2ff958d0'
41
'e49929c27a91610262e4d9ea3bb39e481effe983d4671ed06d349f523c1a6180'
42
'SKIP'
43
'0e038a4f0a2799f6aaa34f6560f5d1d41fba0cf26f8814571cebc94f5bb67a6e'
44
45
'196886b557e632547d32354f20834e88ba3726df29a486c85d6409900064f364'
46
'e8dae4079a66d5a1564c577bd27caf8c890a1044d9c56948581591e196e4ac8c'
47
'66c7c35ed9a46bd27e3d915dcf9a05e38b3f5ebb039883b92aa62ffea20fb187'
48
'2a9b98ebecaede62665ef427b05b3a5ccdac7bd3202414fc0f4c10825b4f4ea2'
49
'78afa2a1c773caf3cf7edf62f857d2a8a5da55fb0fff5da416074c0d28b2b55f'
50
'b0fd5df54a2b281348ab03c2942b1e83278bee62c71e06d3d671724b49946593'
51
)
52
53
build() {
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
64
compile() {
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
101
legendary_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
)
108
heroic_prefixes=(
109
"$HOME/.config/heroic/GamesConfig/Sugar.json"
110
"$HOME/.var/app/com.heroicgameslauncher.hgl/config/heroic/GamesConfig/Sugar.json"
111
)
112
heroic_global=(
113
"$HOME/.config/heroic/config.json"
114
"$HOME/.var/app/com.heroicgameslauncher.hgl/config/heroic/config.json"
115
)
116
wine_bm_path="drive_c/users/steamuser/AppData/Roaming/bakkesmod"
117
118
installed_version() {
119
jq -er .Sugar.version < "$1"
120
}
121
122
install_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
135
wine_pfx() {
136
pfx=`jq -er .Sugar.install_path < "$1"`
137
echo "$(dirname "$pfx")/Prefixes/default/Rocket League"
138
}
139
140
heroic_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
149
heroic_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
158
build_version() {
159
RL_version="$(installed_version "$1")"
160
echo "$RL_version.$( cat "$srcdir/version.txt" ).$pkgver.$pkgrel"
161
}
162
163
powershell_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
168
powershell() {
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
186
package() {
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
303
pre_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) | Severity | Rules |
|---|---|---|
| 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 |