High severity8.8NVD Advisory· Published Jun 8, 2017· Updated May 13, 2026
CVE-2014-3498
CVE-2014-3498
Description
The user module in ansible before 1.6.6 allows remote authenticated users to execute arbitrary commands.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
ansiblePyPI | < 1.6.6 | 1.6.6 |
Affected products
1Patches
18ed6350e65c8When parsing json from untrusted sources, remove templating tags
5 files changed · +41 −19
lib/ansible/inventory/script.py+1 −1 modified@@ -49,7 +49,7 @@ def __init__(self, filename=C.DEFAULT_HOST_LIST): def _parse(self, err): all_hosts = {} - self.raw = utils.parse_json(self.data) + self.raw = utils.parse_json(self.data, from_remote=True) all = Group('all') groups = dict(all=all) group = None
lib/ansible/runner/__init__.py+1 −1 modified@@ -497,7 +497,7 @@ def _execute_module(self, conn, tmp, module_name, args, cmd2 = conn.shell.remove(tmp, recurse=True) self._low_level_exec_command(conn, cmd2, tmp, sudoable=False) - data = utils.parse_json(res['stdout']) + data = utils.parse_json(res['stdout'], from_remote=True) if 'parsed' in data and data['parsed'] == False: data['msg'] += res['stderr'] return ReturnData(conn=conn, result=data)
lib/ansible/runner/return_data.py+1 −2 modified@@ -43,8 +43,7 @@ def __init__(self, conn=None, host=None, result=None, self.diff = diff if type(self.result) in [ str, unicode ]: - self.result = utils.parse_json(self.result) - + self.result = utils.parse_json(self.result, from_remote=True) if self.host is None: raise Exception("host not set")
lib/ansible/utils/__init__.py+38 −4 modified@@ -313,7 +313,38 @@ def json_loads(data): return json.loads(data) -def parse_json(raw_data): +def _clean_data(orig_data): + ''' remove template tags from a string ''' + data = orig_data + if isinstance(orig_data, basestring): + for pattern,replacement in (('{{','{#'), ('}}','#}'), ('{%','{#'), ('%}','#}')): + data = data.replace(pattern, replacement) + return data + +def _clean_data_struct(orig_data): + ''' + walk a complex data structure, and use _clean_data() to + remove any template tags that may exist + ''' + if isinstance(orig_data, dict): + data = orig_data.copy() + for key in data: + new_key = _clean_data_struct(key) + new_val = _clean_data_struct(data[key]) + if key != new_key: + del data[key] + data[new_key] = new_val + elif isinstance(orig_data, list): + data = orig_data[:] + for i in range(0, len(data)): + data[i] = _clean_data_struct(data[i]) + elif isinstance(orig_data, basestring): + data = _clean_data(orig_data) + else: + data = orig_data + return data + +def parse_json(raw_data, from_remote=False): ''' this version for module return data only ''' orig_data = raw_data @@ -322,7 +353,7 @@ def parse_json(raw_data): data = filter_leading_non_json_lines(raw_data) try: - return json.loads(data) + results = json.loads(data) except: # not JSON, but try "Baby JSON" which allows many of our modules to not # require JSON and makes writing modules in bash much simpler @@ -332,7 +363,6 @@ def parse_json(raw_data): except: print "failed to parse json: "+ data raise - for t in tokens: if "=" not in t: raise errors.AnsibleError("failed to parse: %s" % orig_data) @@ -347,7 +377,11 @@ def parse_json(raw_data): results[key] = value if len(results.keys()) == 0: return { "failed" : True, "parsed" : False, "msg" : orig_data } - return results + + if from_remote: + results = _clean_data_struct(results) + + return results def smush_braces(data): ''' smush Jinaj2 braces so unresolved templates like {{ foo }} don't get parsed weird by key=value code '''
lib/ansible/utils/template.py+0 −11 modified@@ -80,7 +80,6 @@ class Flags: FILTER_PLUGINS = None _LISTRE = re.compile(r"(\w+)\[(\d+)\]") -JINJA2_OVERRIDE='#jinja2:' def lookup(name, *args, **kwargs): from ansible import utils @@ -231,16 +230,6 @@ def my_finalize(thing): except: raise errors.AnsibleError("unable to read %s" % realpath) - - # Get jinja env overrides from template - if data.startswith(JINJA2_OVERRIDE): - eol = data.find('\n') - line = data[len(JINJA2_OVERRIDE):eol] - data = data[eol+1:] - for pair in line.split(','): - (key,val) = pair.split(':') - setattr(environment,key.strip(),ast.literal_eval(val.strip())) - environment.template_class = J2Template try: t = environment.from_string(data)
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/ansible/ansible/commit/8ed6350e65c82292a631f08845dfaacffe7f07f5nvdPatchThird Party AdvisoryWEB
- bugzilla.redhat.com/show_bug.cginvdIssue TrackingThird Party AdvisoryWEB
- github.com/advisories/GHSA-4cvm-5776-jx9fghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2014-3498ghsaADVISORY
- github.com/pypa/advisory-database/tree/main/vulns/ansible/PYSEC-2017-2.yamlghsaWEB
News mentions
0No linked articles in our index yet.