diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am
index bcb90071103228b06a6b26836f6f9a981823f9b4..e77e6c31817f689a2e4ab29f9bfb0c977fa414ef 100644
--- a/src/lib-sieve/Makefile.am
+++ b/src/lib-sieve/Makefile.am
@@ -57,6 +57,7 @@ libsieve_la_DEPENDENCIES = $(plugins)
 libsieve_la_LIBADD = $(plugins)
 
 libsieve_la_SOURCES = \
+	sieve-limits.c \
 	sieve-message.c \
 	sieve-lexer.c \
 	sieve-script.c \
diff --git a/src/lib-sieve/sieve-limits.c b/src/lib-sieve/sieve-limits.c
new file mode 100644
index 0000000000000000000000000000000000000000..624e702007cf0780689de5a8cf1838bb58da51a5
--- /dev/null
+++ b/src/lib-sieve/sieve-limits.c
@@ -0,0 +1,9 @@
+/* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file
+ */
+
+#include "sieve-common.h"
+#include "sieve-limits.h"
+
+unsigned int sieve_max_actions = SIEVE_DEFAULT_MAX_ACTIONS;
+unsigned int sieve_max_redirects = SIEVE_DEFAULT_MAX_REDIRECTS;
+
diff --git a/src/lib-sieve/sieve-limits.h b/src/lib-sieve/sieve-limits.h
index d5cceda1483e05cd0d4ce000d7e0c72864dec37f..375815afb96f5138c47f2173ee93e273dcf1c235 100644
--- a/src/lib-sieve/sieve-limits.h
+++ b/src/lib-sieve/sieve-limits.h
@@ -29,7 +29,10 @@
  * Actions
  */
 
-#define SIEVE_DEFAULT_MAX_REDIRECTS 4
 #define SIEVE_DEFAULT_MAX_ACTIONS   32
+#define SIEVE_DEFAULT_MAX_REDIRECTS 4
+
+extern unsigned int sieve_max_actions;
+extern unsigned int sieve_max_redirects;
 
 #endif /* __SIEVE_LIMITS_H */
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 22bd2360984d0b987276af784bcd021a294370c1..24d6f0b1e76d636cda2098f4263caff03b16b085 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -10,6 +10,7 @@
 #include "str-sanitize.h"
 
 #include "sieve-common.h"
+#include "sieve-limits.h"
 #include "sieve-script.h"
 #include "sieve-error.h"
 #include "sieve-interpreter.h"
@@ -49,7 +50,7 @@ struct sieve_result_side_effect {
 	struct sieve_result_side_effect *prev, *next; 
 };
 
-struct sieve_result_implicit_side_effects {
+struct sieve_result_action_context {
 	const struct sieve_action *action;
 	struct sieve_side_effects_list *seffects;
 };
@@ -68,10 +69,12 @@ struct sieve_result {
 	struct sieve_error_handler *ehandler;
 		
 	struct sieve_action_exec_env action_env;
+
+	unsigned int action_count;
 	struct sieve_result_action *first_action;
 	struct sieve_result_action *last_action;
 	
-	struct hash_table *implicit_seffects;
+	struct hash_table *action_contexts;
 };
 
 struct sieve_result *sieve_result_create
@@ -92,10 +95,11 @@ struct sieve_result *sieve_result_create
 
 	result->action_env.result = result;
 		
+	result->action_count = 0;
 	result->first_action = NULL;
 	result->last_action = NULL;
 
-	result->implicit_seffects = NULL;
+	result->action_contexts = NULL;
 	return result;
 }
 
@@ -111,8 +115,8 @@ void sieve_result_unref(struct sieve_result **result)
 	if (--(*result)->refcount != 0)
 		return;
 
-	if ( (*result)->implicit_seffects != NULL )
-        hash_destroy(&(*result)->implicit_seffects);
+	if ( (*result)->action_contexts != NULL )
+        hash_destroy(&(*result)->action_contexts);
 
 	sieve_error_handler_unref(&(*result)->ehandler);
 
@@ -198,27 +202,27 @@ void sieve_result_add_implicit_side_effect
 (struct sieve_result *result, const struct sieve_action *to_action, 
 	const struct sieve_side_effect *seffect, void *context)
 {
-	struct sieve_result_implicit_side_effects *implseff = NULL;
+	struct sieve_result_action_context *actctx = NULL;
 	
-	if ( result->implicit_seffects == NULL ) {
-		result->implicit_seffects = hash_create
+	if ( result->action_contexts == NULL ) {
+		result->action_contexts = hash_create
 			(default_pool, result->pool, 0, NULL, NULL);
 	} else {
-		implseff = (struct sieve_result_implicit_side_effects *) 
-			hash_lookup(result->implicit_seffects, to_action);
+		actctx = (struct sieve_result_action_context *) 
+			hash_lookup(result->action_contexts, to_action);
 	}
 
-	if ( implseff == NULL ) {
-		implseff = p_new
-			(result->pool, struct sieve_result_implicit_side_effects, 1);
-		implseff->action = to_action;
-		implseff->seffects = sieve_side_effects_list_create(result);
+	if ( actctx == NULL ) {
+		actctx = p_new
+			(result->pool, struct sieve_result_action_context, 1);
+		actctx->action = to_action;
+		actctx->seffects = sieve_side_effects_list_create(result);
 		
-		hash_insert(result->implicit_seffects, (void *) to_action, 
-			(void *) implseff);
+		hash_insert(result->action_contexts, (void *) to_action, 
+			(void *) actctx);
 	}	
 	
-	sieve_side_effects_list_add(implseff->seffects, seffect, context);
+	sieve_side_effects_list_add(actctx->seffects, seffect, context);
 }
 
 int sieve_result_add_action
@@ -260,6 +264,12 @@ int sieve_result_add_action
 		}
 		raction = raction->next;
 	}
+
+	/* Check policy limit on number of actions */
+	if ( result->action_count >= sieve_max_actions ) {
+		sieve_runtime_error(renv, location, "number of actions exceeds policy limit");
+		return -1;
+	}
 		
 	/* Create new action object */
 	raction = p_new(result->pool, struct sieve_result_action, 1);
@@ -282,23 +292,24 @@ int sieve_result_add_action
 		raction->prev = result->last_action;
 		result->last_action = raction;
 		raction->next = NULL;
-	}	
+	}
+	result->action_count++;
 	
 	/* Apply any implicit side effects */
-	if ( result->implicit_seffects != NULL ) {
-		struct sieve_result_implicit_side_effects *implseff;
+	if ( result->action_contexts != NULL ) {
+		struct sieve_result_action_context *actctx;
 		
 		/* Check for implicit side effects to this particular action */
-		implseff = (struct sieve_result_implicit_side_effects *) 
-				hash_lookup(result->implicit_seffects, action);
+		actctx = (struct sieve_result_action_context *) 
+				hash_lookup(result->action_contexts, action);
 		
-		if ( implseff != NULL ) {
+		if ( actctx != NULL ) {
 			struct sieve_result_side_effect *iseff;
 			
 			/* Iterate through all implicit side effects and add those that are 
 			 * missing.
 			 */
-			iseff = implseff->seffects->first_effect;
+			iseff = actctx->seffects->first_effect;
 			while ( iseff != NULL ) {
 				struct sieve_result_side_effect *seff;
 				bool exists = FALSE;
@@ -438,20 +449,19 @@ bool sieve_result_implicit_keep
 	ctx.folder = result->action_env.scriptenv->inbox;
 	
 	/* Also apply any implicit side effects if applicable */
-	if ( !rollback && result->implicit_seffects != NULL ) {
-		struct sieve_result_implicit_side_effects *implseff;
+	if ( !rollback && result->action_contexts != NULL ) {
+		struct sieve_result_action_context *actctx;
 		
 		/* Check for implicit side effects to store action */
-		implseff = (struct sieve_result_implicit_side_effects *) 
-				hash_lookup(result->implicit_seffects, &act_store);
+		actctx = (struct sieve_result_action_context *) 
+				hash_lookup(result->action_contexts, &act_store);
 		
-		if ( implseff != NULL && implseff->seffects != NULL ) 
-			rsef_first = implseff->seffects->first_effect;
+		if ( actctx != NULL && actctx->seffects != NULL ) 
+			rsef_first = actctx->seffects->first_effect;
 		
 	}
 	
-	success = act_store.start
-		(&act_store, &result->action_env, (void *) &ctx, &tr_context);
+	success = act_store.start(&act_store, &result->action_env, (void *) &ctx, &tr_context);
 
 	rsef = rsef_first;
 	while ( rsef != NULL ) {
@@ -512,7 +522,7 @@ int sieve_result_execute
 	
 	/* 
 	 * Transaction start 
-   */
+	 */
 	
 	rac = result->first_action;
 	while ( success && rac != NULL ) {
diff --git a/tests/execute/errors.svtest b/tests/execute/errors.svtest
index 196d5fb9792b31511af575c886e239963c4847eb..60842f308747dfd6dd62270f41510d2063501f94 100644
--- a/tests/execute/errors.svtest
+++ b/tests/execute/errors.svtest
@@ -44,3 +44,21 @@ test "Action conflicts: reject <-> redirect" {
 		test_fail "too many runtime errors reported";
 	}
 }
+
+test "Action limits" {
+	if not test_compile "errors/actions-limit.sieve" {
+		test_fail "compile failed";
+	}
+
+	if test_execute {
+		test_fail "execution should have failed";
+	}
+
+	if test_error :count "gt" :comparator "i;ascii-numeric" "1" {
+		test_fail "too many runtime errors reported";
+	}
+	
+	if not test_error :index 1 :contains "number of actions exceeds policy limit"{
+		test_fail "unexpected error reported";
+	}
+}
diff --git a/tests/execute/errors/actions-limit.sieve b/tests/execute/errors/actions-limit.sieve
new file mode 100644
index 0000000000000000000000000000000000000000..5f0421849846d6bb8d76ed524994296c2b740bf4
--- /dev/null
+++ b/tests/execute/errors/actions-limit.sieve
@@ -0,0 +1,35 @@
+require "fileinto";
+
+fileinto "box1";
+fileinto "box2";
+fileinto "box3";
+fileinto "box4";
+fileinto "box5";
+fileinto "box6";
+fileinto "box7";
+fileinto "box8";
+fileinto "box9";
+fileinto "box10";
+fileinto "box11";
+fileinto "box12";
+fileinto "box13";
+fileinto "box14";
+fileinto "box15";
+fileinto "box16";
+redirect "address1@example.com";
+redirect "address2@example.com";
+redirect "address3@example.com";
+redirect "address4@example.com";
+redirect "address5@example.com";
+redirect "address6@example.com";
+redirect "address7@example.com";
+redirect "address8@example.com";
+redirect "address9@example.com";
+redirect "address10@example.com";
+redirect "address11@example.com";
+redirect "address12@example.com";
+redirect "address13@example.com";
+redirect "address14@example.com";
+redirect "address15@example.com";
+redirect "address16@example.com";
+keep;