CVE-2014-1859
Description
NumPy before 1.8.1 uses insecure temporary file handling, allowing local attackers to overwrite arbitrary files via symlink attacks.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
NumPy before 1.8.1 uses insecure temporary file handling, allowing local attackers to overwrite arbitrary files via symlink attacks.
Vulnerability
NumPy versions before 1.8.1 contain insecure temporary file usage in four locations: core/tests/test_memmap.py, core/tests/test_multiarray.py, f2py/f2py2e.py, and lib/tests/test_io.py [1][2][3]. The code creates temporary files using functions like tempfile.mktemp() without proper precautions against symlink attacks, allowing an attacker to predict or control the temporary file path [4].
Exploitation
An attacker with local access can exploit this by watching for the creation of temporary files by NumPy and then placing a symbolic link at the predicted path pointing to an arbitrary target file the attacker wants to overwrite. When NumPy writes to the temporary file, the write is redirected to the target file, overwriting its contents. No special privileges beyond local user access and the ability to create symlinks in the temporary directory are required [1][2][4].
Impact
Successful exploitation allows a local attacker to write to arbitrary files on the system, potentially leading to escalation of privileges, data corruption, or denial of service. The attacker gains the ability to overwrite any file writable by the user running NumPy, such as configuration files, scripts, or other sensitive data [1][2][4].
Mitigation
The issue was fixed in NumPy version 1.8.1, released on 2014-02-09. The fix removed the insecure use of mktemp and switched to safer temporary file creation methods [3]. Users should upgrade to NumPy 1.8.1 or later. No workaround is available for earlier versions; individual scripts may be patched as a temporary measure [4]. The vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog as of now.
AI Insight generated on May 22, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
numpyPyPI | < 1.8.1 | 1.8.1 |
Affected products
2- osv-coords2 versions
< 1:1.8.1~rc1-1+ 1 more
- (no CPE)range: < 1:1.8.1~rc1-1
- (no CPE)range: < 1.8.1
Patches
10bb46c1448b0ENH: remove insecure mktemp use
5 files changed · +50 −51
numpy/core/tests/test_memmap.py+16 −18 modified@@ -1,7 +1,7 @@ from __future__ import division, absolute_import, print_function import sys -from tempfile import NamedTemporaryFile, TemporaryFile, mktemp +from tempfile import NamedTemporaryFile, TemporaryFile import os from numpy import memmap @@ -33,12 +33,11 @@ def test_roundtrip(self): assert_array_equal(self.data, newfp) def test_open_with_filename(self): - tmpname = mktemp('', 'mmap') - fp = memmap(tmpname, dtype=self.dtype, mode='w+', - shape=self.shape) - fp[:] = self.data[:] - del fp - os.unlink(tmpname) + with NamedTemporaryFile() as tmp: + fp = memmap(tmp.name, dtype=self.dtype, mode='w+', + shape=self.shape) + fp[:] = self.data[:] + del fp def test_unnamed_file(self): with TemporaryFile() as f: @@ -55,17 +54,16 @@ def test_attributes(self): del fp def test_filename(self): - tmpname = mktemp('', 'mmap') - fp = memmap(tmpname, dtype=self.dtype, mode='w+', - shape=self.shape) - abspath = os.path.abspath(tmpname) - fp[:] = self.data[:] - self.assertEqual(abspath, fp.filename) - b = fp[:1] - self.assertEqual(abspath, b.filename) - del b - del fp - os.unlink(tmpname) + with NamedTemporaryFile() as tmp: + fp = memmap(tmp.name, dtype=self.dtype, mode='w+', + shape=self.shape) + abspath = os.path.abspath(tmp.name) + fp[:] = self.data[:] + self.assertEqual(abspath, fp.filename) + b = fp[:1] + self.assertEqual(abspath, b.filename) + del b + del fp def test_filename_fileobj(self): fp = memmap(self.tmpfp, dtype=self.dtype, mode="w+",
numpy/core/tests/test_multiarray.py+3 −10 modified@@ -2316,12 +2316,11 @@ def setUp(self): self.x = rand(shape) + rand(shape).astype(np.complex)*1j self.x[0,:, 1] = [nan, inf, -inf, nan] self.dtype = self.x.dtype - self.filename = tempfile.mktemp() + self.file = tempfile.NamedTemporaryFile() + self.filename = self.file.name def tearDown(self): - if os.path.isfile(self.filename): - os.unlink(self.filename) - #tmp_file.close() + self.file.close() def test_bool_fromstring(self): v = np.array([True, False, True, False], dtype=np.bool_) @@ -2349,7 +2348,6 @@ def test_roundtrip_file(self): y = np.fromfile(f, dtype=self.dtype) f.close() assert_array_equal(y, self.x.flat) - os.unlink(self.filename) def test_roundtrip_filename(self): self.x.tofile(self.filename) @@ -2402,8 +2400,6 @@ def test_file_position_after_fromfile(self): f.close() assert_equal(pos, 10, err_msg=err_msg) - os.unlink(self.filename) - def test_file_position_after_tofile(self): # gh-4118 sizes = [io.DEFAULT_BUFFER_SIZE//8, @@ -2431,8 +2427,6 @@ def test_file_position_after_tofile(self): f.close() assert_equal(pos, 10, err_msg=err_msg) - os.unlink(self.filename) - def _check_from(self, s, value, **kw): y = np.fromstring(asbytes(s), **kw) assert_array_equal(y, value) @@ -2535,7 +2529,6 @@ def test_tofile_sep(self): s = f.read() f.close() assert_equal(s, '1.51,2.0,3.51,4.0') - os.unlink(self.filename) def test_tofile_format(self): x = np.array([1.51, 2, 3.51, 4], dtype=float)
numpy/f2py/f2py2e.py+2 −2 modified@@ -91,7 +91,7 @@ --lower is assumed with -h key, and --no-lower without -h key. --build-dir <dirname> All f2py generated files are created in <dirname>. - Default is tempfile.mktemp(). + Default is tempfile.mkdtemp(). --overwrite-signature Overwrite existing signature file. @@ -424,7 +424,7 @@ def run_compile(): del sys.argv[i] else: remove_build_dir = 1 - build_dir = os.path.join(tempfile.mktemp()) + build_dir = tempfile.mkdtemp() _reg1 = re.compile(r'[-][-]link[-]') sysinfo_flags = [_m for _m in sys.argv[1:] if _reg1.match(_m)]
numpy/f2py/__init__.py+13 −13 modified@@ -28,20 +28,20 @@ def compile(source, from numpy.distutils.exec_command import exec_command import tempfile if source_fn is None: - fname = os.path.join(tempfile.mktemp()+'.f') + f = tempfile.NamedTemporaryFile(suffix='.f') else: - fname = source_fn - - f = open(fname, 'w') - f.write(source) - f.close() - - args = ' -c -m %s %s %s'%(modulename, fname, extra_args) - c = '%s -c "import numpy.f2py as f2py2e;f2py2e.main()" %s' %(sys.executable, args) - s, o = exec_command(c) - if source_fn is None: - try: os.remove(fname) - except OSError: pass + f = open(source_fn, 'w') + + try: + f.write(source) + f.flush() + + args = ' -c -m %s %s %s'%(modulename, f.name, extra_args) + c = '%s -c "import numpy.f2py as f2py2e;f2py2e.main()" %s' % \ + (sys.executable, args) + s, o = exec_command(c) + finally: + f.close() return s from numpy.testing import Tester
numpy/lib/tests/test_io.py+16 −8 modified@@ -4,7 +4,9 @@ import gzip import os import threading -from tempfile import mkstemp, mktemp, NamedTemporaryFile +import shutil +import contextlib +from tempfile import mkstemp, mkdtemp, NamedTemporaryFile import time import warnings import gc @@ -21,6 +23,12 @@ assert_raises, run_module_suite) from numpy.testing import assert_warns, assert_, build_err_msg +@contextlib.contextmanager +def tempdir(change_dir=False): + tmpdir = mkdtemp() + yield tmpdir + shutil.rmtree(tmpdir) + class TextIO(BytesIO): """Helper IO class. @@ -177,14 +185,14 @@ def roundtrip(self, *args, **kwargs): @np.testing.dec.slow def test_big_arrays(self): L = (1 << 31) + 100000 - tmp = mktemp(suffix='.npz') a = np.empty(L, dtype=np.uint8) - np.savez(tmp, a=a) - del a - npfile = np.load(tmp) - a = npfile['a'] - npfile.close() - os.remove(tmp) + with tempdir() as tmpdir: + tmp = open(os.path.join(tmpdir, "file.npz"), "w") + np.savez(tmp, a=a) + del a + npfile = np.load(tmp) + a = npfile['a'] + npfile.close() def test_multiple_arrays(self): a = np.array([[1, 2], [3, 4]], float)
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
14- lists.fedoraproject.org/pipermail/package-announce/2014-February/128358.htmlghsavendor-advisoryx_refsource_FEDORAWEB
- lists.fedoraproject.org/pipermail/package-announce/2014-February/128781.htmlghsavendor-advisoryx_refsource_FEDORAWEB
- github.com/advisories/GHSA-2fc2-6r4j-p65hghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2014-1859ghsaADVISORY
- www.openwall.com/lists/oss-security/2014/02/08/3ghsamailing-listx_refsource_MLISTWEB
- www.securityfocus.com/bid/65440mitrevdb-entryx_refsource_BID
- bugs.debian.org/cgi-bin/bugreport.cgighsax_refsource_CONFIRMWEB
- bugzilla.redhat.com/show_bug.cgighsax_refsource_CONFIRMWEB
- exchange.xforce.ibmcloud.com/vulnerabilities/91317ghsavdb-entryx_refsource_XFWEB
- github.com/numpy/numpy/blob/maintenance/1.8.x/doc/release/1.8.1-notes.rstghsax_refsource_CONFIRMWEB
- github.com/numpy/numpy/commit/0bb46c1448b0d3f5453d5182a17ea7ac5854ee15ghsax_refsource_CONFIRMWEB
- github.com/numpy/numpy/pull/4262ghsax_refsource_CONFIRMWEB
- github.com/pypa/advisory-database/tree/main/vulns/numpy/PYSEC-2018-34.yamlghsaWEB
- web.archive.org/web/20200228165750/http://www.securityfocus.com/bid/65440ghsaWEB
News mentions
0No linked articles in our index yet.