VYPR
Critical severityNVD Advisory· Published Sep 29, 2015· Updated May 6, 2026

CVE-2015-7337

CVE-2015-7337

Description

The editor in IPython Notebook before 3.2.2 and Jupyter Notebook 4.0.x before 4.0.5 allows remote attackers to execute arbitrary JavaScript code via a crafted file, which triggers a redirect to files/, related to MIME types.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
notebookPyPI
>= 4.0.0, < 4.0.54.0.5
ipythonPyPI
< 3.2.23.2.2

Patches

2
0a8096adf165

Merge edit-redirect fix for 3.x

https://github.com/ipython/ipythonMin RKSep 16, 2015via ghsa
5 files changed · +22 20
  • IPython/html/files/handlers.py+5 0 modified
    @@ -40,6 +40,11 @@ def get(self, path):
                 cur_mime = mimetypes.guess_type(name)[0]
                 if cur_mime is not None:
                     self.set_header('Content-Type', cur_mime)
    +            else:
    +                if model['format'] == 'base64':
    +                    self.set_header('Content-Type', 'application/octet-stream')
    +                else:
    +                    self.set_header('Content-Type', 'text/plain')
             
             if model['format'] == 'base64':
                 b64_bytes = model['content'].encode('ascii')
    
  • IPython/html/services/contents/filemanager.py+7 5 modified
    @@ -277,18 +277,20 @@ def _file_model(self, path, content=True, format=None):
             model['type'] = 'file'
     
             os_path = self._get_os_path(path)
    +        model['mimetype'] = mimetypes.guess_type(os_path)[0]
     
             if content:
                 content, format = self._read_file(os_path, format)
    -            default_mime = {
    -                'text': 'text/plain',
    -                'base64': 'application/octet-stream'
    -            }[format]
    +            if model['mimetype'] is None:
    +                default_mime = {
    +                    'text': 'text/plain',
    +                    'base64': 'application/octet-stream'
    +                }[format]
    +                model['mimetype'] = default_mime
     
                 model.update(
                     content=content,
                     format=format,
    -                mimetype=mimetypes.guess_type(os_path)[0] or default_mime,
                 )
     
             return model
    
  • IPython/html/services/contents/handlers.py+0 3 modified
    @@ -52,9 +52,6 @@ def validate_model(model, expect_content):
             )
     
         maybe_none_keys = ['content', 'format']
    -    if model['type'] == 'file':
    -        # mimetype should be populated only for file models
    -        maybe_none_keys.append('mimetype')
         if expect_content:
             errors = [key for key in maybe_none_keys if model[key] is None]
             if errors:
    
  • IPython/html/static/edit/js/editor.js+3 12 modified
    @@ -90,19 +90,10 @@ function($,
                 }).catch(
                 function(error) {
                     that.events.trigger("file_load_failed.Editor", error);
    -                if (((error.xhr||{}).responseJSON||{}).reason === 'bad format') {
    -                    window.location = utils.url_path_join(
    -                        that.base_url,
    -                        'files',
    -                        that.file_path
    -                    );
    -                } else {
    -                    console.warn('Error while loading: the error was:')
    -                    console.warn(error)
    -                }
    +                console.warn('Error loading: ', error);
                     cm.setValue("Error! " + error.message +
                                     "\nSaving disabled.\nSee Console for more details.");
    -                cm.setOption('readOnly','nocursor')
    +                cm.setOption('readOnly','nocursor');
                     that.save_enabled = false;
                 }
             );
    @@ -186,7 +177,7 @@ function($,
         Editor.prototype._clean_state = function(){
             var clean = this.codemirror.isClean(this.generation);
             if (clean === this.clean){
    -            return
    +            return;
             } else {
                 this.clean = clean;
             }
    
  • IPython/html/static/tree/js/notebooklist.js+7 0 modified
    @@ -532,6 +532,13 @@ define([
                 icon = 'running_' + icon;
             }
             var uri_prefix = NotebookList.uri_prefixes[model.type];
    +        if (model.type === 'file' &&
    +            model.mimetype && model.mimetype.substr(0,5) !== 'text/'
    +        ) {
    +            // send text/unidentified files to editor, others go to raw viewer
    +            uri_prefix = 'files';
    +        }
    +        
             item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
             var link = item.find("a.item_link")
                 .attr('href',
    
9e63dd89b603

Merge edit-redirect fix into 4.0.x

https://github.com/jupyter/notebookMin RKSep 16, 2015via ghsa
5 files changed · +22 20
  • notebook/files/handlers.py+5 0 modified
    @@ -40,6 +40,11 @@ def get(self, path):
                 cur_mime = mimetypes.guess_type(name)[0]
                 if cur_mime is not None:
                     self.set_header('Content-Type', cur_mime)
    +            else:
    +                if model['format'] == 'base64':
    +                    self.set_header('Content-Type', 'application/octet-stream')
    +                else:
    +                    self.set_header('Content-Type', 'text/plain')
             
             if model['format'] == 'base64':
                 b64_bytes = model['content'].encode('ascii')
    
  • notebook/services/contents/filemanager.py+7 5 modified
    @@ -278,18 +278,20 @@ def _file_model(self, path, content=True, format=None):
             model['type'] = 'file'
     
             os_path = self._get_os_path(path)
    +        model['mimetype'] = mimetypes.guess_type(os_path)[0]
     
             if content:
                 content, format = self._read_file(os_path, format)
    -            default_mime = {
    -                'text': 'text/plain',
    -                'base64': 'application/octet-stream'
    -            }[format]
    +            if model['mimetype'] is None:
    +                default_mime = {
    +                    'text': 'text/plain',
    +                    'base64': 'application/octet-stream'
    +                }[format]
    +                model['mimetype'] = default_mime
     
                 model.update(
                     content=content,
                     format=format,
    -                mimetype=mimetypes.guess_type(os_path)[0] or default_mime,
                 )
     
             return model
    
  • notebook/services/contents/handlers.py+0 3 modified
    @@ -55,9 +55,6 @@ def validate_model(model, expect_content):
             )
     
         maybe_none_keys = ['content', 'format']
    -    if model['type'] == 'file':
    -        # mimetype should be populated only for file models
    -        maybe_none_keys.append('mimetype')
         if expect_content:
             errors = [key for key in maybe_none_keys if model[key] is None]
             if errors:
    
  • notebook/static/edit/js/editor.js+3 12 modified
    @@ -90,19 +90,10 @@ function($,
                 }).catch(
                 function(error) {
                     that.events.trigger("file_load_failed.Editor", error);
    -                if (((error.xhr||{}).responseJSON||{}).reason === 'bad format') {
    -                    window.location = utils.url_path_join(
    -                        that.base_url,
    -                        'files',
    -                        that.file_path
    -                    );
    -                } else {
    -                    console.warn('Error while loading: the error was:')
    -                    console.warn(error)
    -                }
    +                console.warn('Error loading: ', error);
                     cm.setValue("Error! " + error.message +
                                     "\nSaving disabled.\nSee Console for more details.");
    -                cm.setOption('readOnly','nocursor')
    +                cm.setOption('readOnly','nocursor');
                     that.save_enabled = false;
                 }
             );
    @@ -186,7 +177,7 @@ function($,
         Editor.prototype._clean_state = function(){
             var clean = this.codemirror.isClean(this.generation);
             if (clean === this.clean){
    -            return
    +            return;
             } else {
                 this.clean = clean;
             }
    
  • notebook/static/tree/js/notebooklist.js+7 0 modified
    @@ -540,6 +540,13 @@ define([
                 icon = 'running_' + icon;
             }
             var uri_prefix = NotebookList.uri_prefixes[model.type];
    +        if (model.type === 'file' &&
    +            model.mimetype && model.mimetype.substr(0,5) !== 'text/'
    +        ) {
    +            // send text/unidentified files to editor, others go to raw viewer
    +            uri_prefix = 'files';
    +        }
    +        
             item.find(".item_icon").addClass(icon).addClass('icon-fixed-width');
             var link = item.find("a.item_link")
                 .attr('href',
    

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

11

News mentions

0

No linked articles in our index yet.