diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py
index 08309e9..93f9e23 100644
--- a/IPython/core/interactiveshell.py
+++ b/IPython/core/interactiveshell.py
@@ -1484,13 +1484,42 @@ class InteractiveShell(SingletonConfigurable, Magic):
             print 'Exception value:',value
             print 'Traceback      :',tb
             #print 'Source code    :','\n'.join(self.buffer)
+        
+        def validate_stb(stb):
+            """validate structured traceback return type
+            
+            return type of CustomTB *should* be a list of strings, but allow
+            single strings or None, which are harmless.
+            
+            This function will *always* return a list of strings,
+            and will raise a TypeError if stb is inappropriate.
+            """
+            msg = "CustomTB must return list of strings, not %r" % stb
+            if stb is None:
+                return []
+            elif isinstance(stb, basestring):
+                return [stb]
+            elif not isinstance(stb, list):
+                raise TypeError(msg)
+            # it's a list
+            for line in stb:
+                # check every element
+                if not isinstance(line, basestring):
+                    raise TypeError(msg)
+            return stb
 
         if handler is None:
             wrapped = dummy_handler
         else:
             def wrapped(self,etype,value,tb,tb_offset=None):
+                """wrap CustomTB handler, to protect IPython from user code
+                
+                This makes it harder (but not impossible) for custom exception
+                handlers to crash IPython.
+                """
                 try:
-                    return handler(self,etype,value,tb,tb_offset=tb_offset)
+                    stb = handler(self,etype,value,tb,tb_offset=tb_offset)
+                    return validate_stb(stb)
                 except:
                     # clear custom handler immediately
                     self.set_custom_exc((), None)
@@ -1499,7 +1528,10 @@ class InteractiveShell(SingletonConfigurable, Magic):
                     stb = self.InteractiveTB.structured_traceback(*sys.exc_info())
                     print >> io.stdout, self.InteractiveTB.stb2text(stb)
                     print >> io.stdout, "The original exception:"
-                    self.showtraceback((etype,value,tb), tb_offset=tb_offset)
+                    stb = self.InteractiveTB.structured_traceback(
+                                            (etype,value,tb), tb_offset=tb_offset
+                    )
+                return stb
 
         self.CustomTB = types.MethodType(wrapped,self)
         self.custom_exceptions = exc_tuple
@@ -1570,11 +1602,7 @@ class InteractiveShell(SingletonConfigurable, Magic):
                 sys.last_value = value
                 sys.last_traceback = tb
                 if etype in self.custom_exceptions:
-                    # FIXME: Old custom traceback objects may just return a
-                    # string, in that case we just put it into a list
                     stb = self.CustomTB(etype, value, tb, tb_offset)
-                    if isinstance(ctb, basestring):
-                        stb = [stb]
                 else:
                     if exception_only:
                         stb = ['An exception has occurred, use %tb to see '
diff --git a/IPython/core/tests/test_interactiveshell.py b/IPython/core/tests/test_interactiveshell.py
index 9e7b848..a0b31b0 100644
--- a/IPython/core/tests/test_interactiveshell.py
+++ b/IPython/core/tests/test_interactiveshell.py
@@ -155,7 +155,7 @@ class InteractiveShellTestCase(unittest.TestCase):
         try:
             # capture stderr
             io.stderr = StringIO()
-            ip.set_custom_exc((IOError,),lambda etype,value,tb: None)
+            ip.set_custom_exc((IOError,), lambda etype,value,tb: 1/0)
             self.assertEquals(ip.custom_exceptions, (IOError,))
             ip.run_cell(u'raise IOError("foo")')
             self.assertEquals(ip.custom_exceptions, ())
@@ -163,4 +163,20 @@ class InteractiveShellTestCase(unittest.TestCase):
         finally:
             io.stderr = save_stderr
 
+    def test_bad_custom_tb_return(self):
+        """Check that InteractiveShell is protected from bad return types in custom exception handlers"""
+        ip = get_ipython()
+        from IPython.utils import io
+        save_stderr = io.stderr
+        try:
+            # capture stderr
+            io.stderr = StringIO()
+            ip.set_custom_exc((NameError,),lambda etype,value,tb, tb_offset=None: 1)
+            self.assertEquals(ip.custom_exceptions, (NameError,))
+            ip.run_cell(u'a=abracadabra')
+            self.assertEquals(ip.custom_exceptions, ())
+            self.assertTrue("Custom TB Handler failed" in io.stderr.getvalue())
+        finally:
+            io.stderr = save_stderr
+