diff --git a/source/texk/web2c/luatexdir/lua/lnodelib.c b/source/texk/web2c/luatexdir/lua/lnodelib.c
index a983240dd..368d05f9c 100644
--- a/source/texk/web2c/luatexdir/lua/lnodelib.c
+++ b/source/texk/web2c/luatexdir/lua/lnodelib.c
@@ -2335,6 +2335,14 @@ static int lua_nodelib_direct_copy(lua_State * L)
 }
 
 
+/* node.scan (scan a box from tex) */
+
+static int lua_nodelib_scan(lua_State * L)
+{
+    lua_nodelib_push_fast(L, local_scan_box());
+    return 1;
+}
+
 /* node.write (output a node to tex's processor) */
 
 static int lua_nodelib_append(lua_State * L)
@@ -8821,6 +8829,9 @@ static const struct luaL_Reg nodelib_f[] = {
     {"whatsits", lua_nodelib_whatsits},
     {"write", lua_nodelib_append},
     /* experiment */
+    {"scan",lua_nodelib_scan},
+    /* experiment */
+    /* experiment */
  /* {"attributes_to_table",lua_nodelib_attributes_to_table}, */
     /* experiment */
     {"set_properties_mode",lua_nodelib_properties_set_mode},
diff --git a/source/texk/web2c/luatexdir/tex/maincontrol.c b/source/texk/web2c/luatexdir/tex/maincontrol.c
index c568d1f68..c03697ecc 100644
--- a/source/texk/web2c/luatexdir/tex/maincontrol.c
+++ b/source/texk/web2c/luatexdir/tex/maincontrol.c
@@ -1060,6 +1060,21 @@ void local_control(int l)
     return;
 }
 
+halfword local_scan_box()
+{
+    int old_mode = mode;
+    int ll = local_level;
+    mode = -hmode;
+    scan_box(lua_box_flag);
+    if(local_level == ll) {
+        local_control(0);
+    } else {
+        local_level = ll;
+    }
+    mode = old_mode;
+    return cur_box;
+}
+
 void app_space(void)
 {                               /* handle spaces when |space_factor<>1000| */
     halfword q;                 /* glue node */
@@ -1570,8 +1585,13 @@ void box_end(int box_context)
             eq_define(box_base + box_context - box_flag, box_ref_cmd, cur_box);
         else
             geq_define(box_base + box_context - global_box_flag, box_ref_cmd, cur_box);
+    } else if (box_context == lua_box_flag) {
+        /*tex
+            We are done with scanning so return to the caller
+        */
+        local_level -= 1;
     } else if (cur_box != null) {
-        if (box_context > ship_out_flag) {
+        if (box_context > lua_box_flag) {
             /*tex
                 Append a new leader node that uses |cur_box| and get the next
                 non-blank non-relax...
@@ -1627,6 +1647,10 @@ void scan_box(int box_context)
             "your output. But keep trying; you can fix this later."
         );
         back_error();
+        if (box_context == lua_box_flag) {
+            cur_box = null;
+            box_end(box_context);
+        }
     }
 }
 
diff --git a/source/texk/web2c/luatexdir/tex/maincontrol.h b/source/texk/web2c/luatexdir/tex/maincontrol.h
index 598c5b7fd..ad7c19330 100644
--- a/source/texk/web2c/luatexdir/tex/maincontrol.h
+++ b/source/texk/web2c/luatexdir/tex/maincontrol.h
@@ -209,4 +209,6 @@ extern int local_level;
 
 extern void local_control(int l);
 
+extern halfword local_scan_box();
+
 #endif
diff --git a/source/texk/web2c/luatexdir/tex/packaging.h b/source/texk/web2c/luatexdir/tex/packaging.h
index 6a0802e46..f1e364e98 100644
--- a/source/texk/web2c/luatexdir/tex/packaging.h
+++ b/source/texk/web2c/luatexdir/tex/packaging.h
@@ -143,6 +143,7 @@ latter two are used denote \.{\\vbox} and \.{\\hbox}, respectively.
 #  define global_box_flag     (box_flag+number_regs)        /* context code for `\.{\\global\\setbox0}' */
 #  define max_global_box_flag (global_box_flag+number_regs)
 #  define ship_out_flag       (max_global_box_flag+1)       /* context code for `\.{\\shipout}' */
+#  define lua_box_flag        (ship_out_flag+1)             /* context code for boxes scanned by lua */
 #  define leader_flag         ship_out_flag+1               /* context code for `\.{\\leaders}' */
 
 extern void begin_box(int box_context);
