diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4a930d6..ed5adff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
+- [#108](https://github.com/green-code-initiative/creedengo-python/pull/108) Add rule GCI109 Avoid using exceptions for control flow
+
 ### Changed
 
 - compatibility updates for SonarQube 25.9.0
diff --git a/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java b/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java
index 4fab77f..7195b1a 100644
--- a/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java
+++ b/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java
@@ -462,4 +462,19 @@ void testGCI108(){
         checkIssuesForFile(filePath, ruleId, ruleMsg, startLines, endLines, SEVERITY, TYPE, EFFORT_10MIN);
     }
 
+    @Test
+    void testGCI109(){
+        String filePath = "src/avoidExceptionsForControlFlow.py";
+        String ruleId = "creedengo-python:GCI109";
+        String ruleMsg = "Avoid using exceptions for control flow";
+        int[] startLines = new int[]{
+            4, 10, 16, 22, 29
+        };
+        int[] endLines = new int[]{
+            4, 10, 16, 22, 29
+        };
+
+        checkIssuesForFile(filePath, ruleId, ruleMsg, startLines, endLines, SEVERITY_MAJOR, TYPE, EFFORT_5MIN);
+    }
+
 }
diff --git a/src/it/test-projects/creedengo-python-plugin-test-project/src/avoidExceptionsForControlFlow.py b/src/it/test-projects/creedengo-python-plugin-test-project/src/avoidExceptionsForControlFlow.py
new file mode 100644
index 0000000..ed483a0
--- /dev/null
+++ b/src/it/test-projects/creedengo-python-plugin-test-project/src/avoidExceptionsForControlFlow.py
@@ -0,0 +1,85 @@
+# using KeyError for control flow
+try:
+    value = my_dict[key]
+except KeyError:  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = default
+
+# using IndexError for control flow
+try:
+    item = my_list[index]
+except IndexError:  # Noncompliant {{Avoid using exceptions for control flow}}
+    item = None
+
+# using AttributeError for control flow
+try:
+    value = obj.attribute
+except AttributeError:  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+#  using StopIteration for control flow
+try:
+    value = next(iterator)
+except StopIteration:  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+# KeyError in loop
+for key in keys:
+    try:
+        values.append(my_dict[key])
+    except KeyError:  # Noncompliant {{Avoid using exceptions for control flow}}
+        values.append(default)
+
+# multiple exceptions in tuple 
+try:
+    value = my_dict[key]
+except (KeyError, ValueError):  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+# multiple control flow exceptions in tuple
+try:
+    item = my_list[index]
+except (IndexError, KeyError):  # Noncompliant {{Avoid using exceptions for control flow}}
+    item = None
+
+# AttributeError with other exceptions in tuple
+try:
+    value = obj.attribute
+except (AttributeError, TypeError):  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+
+
+### Compliant cases ###
+value = my_dict.get(key, default)
+
+
+
+if 0 <= index < len(my_list):
+    item = my_list[index]
+else:
+    item = None
+
+
+
+value = getattr(obj, 'attribute', None)
+
+
+value = next(iterator, None)
+
+
+try:
+    result = risky_operation()
+except ValueError:
+    result = None
+
+
+
+try:
+    process_file()
+except (IOError, OSError):
+    handle_error()
+
+
+
+for key in keys:
+    values.append(my_dict.get(key, default))
diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java
index ad4955e..d284739 100644
--- a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java
+++ b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java
@@ -50,7 +50,8 @@ public record PythonRuleRepository(SonarRuntime sonarRuntime) implements RulesDe
             DisableGradientForModelEval.class,
             StringConcatenation.class,
             PreferAppendLeft.class,
-            AvoidCreatingTensorUsingNumpyOrNativePython.class
+            AvoidCreatingTensorUsingNumpyOrNativePython.class,
+            AvoidExceptionsForControlFlowCheck.class
     );
 
     public static final String LANGUAGE = "py";
diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidExceptionsForControlFlowCheck.java b/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidExceptionsForControlFlowCheck.java
new file mode 100644
index 0000000..b545004
--- /dev/null
+++ b/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidExceptionsForControlFlowCheck.java
@@ -0,0 +1,80 @@
+/*
+ * creedengo - Python language - Provides rules to reduce the environmental footprint of your Python programs
+ * Copyright © 2024 Green Code Initiative (https://green-code-initiative.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.greencodeinitiative.creedengo.python.checks;
+
+import org.sonar.check.Rule;
+import org.sonar.plugins.python.api.PythonSubscriptionCheck;
+import org.sonar.plugins.python.api.SubscriptionContext;
+import org.sonar.plugins.python.api.tree.ExceptClause;
+import org.sonar.plugins.python.api.tree.Expression;
+import org.sonar.plugins.python.api.tree.Tree;
+import org.sonar.plugins.python.api.tree.TryStatement;
+import org.sonar.plugins.python.api.tree.Tuple;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Rule(key = "GCI109")
+public class AvoidExceptionsForControlFlowCheck extends PythonSubscriptionCheck {
+
+    public static final String DESCRIPTION = "Avoid using exceptions for control flow";
+    
+    private static final List CONTROL_FLOW_EXCEPTIONS = Arrays.asList(
+        "KeyError",
+        "IndexError",
+        "AttributeError",
+        "StopIteration"
+    );
+
+    @Override
+    public void initialize(Context context) {
+        context.registerSyntaxNodeConsumer(Tree.Kind.TRY_STMT, this::visitTryStatement);
+    }
+
+    private void visitTryStatement(SubscriptionContext context) {
+        TryStatement tryStatement = (TryStatement) context.syntaxNode();
+        
+        List exceptClauses = tryStatement.exceptClauses();
+        if (exceptClauses.isEmpty()) {
+            return;
+        }
+        
+        for (ExceptClause exceptClause : exceptClauses) {
+            Expression exception = exceptClause.exception();
+            if (exception != null && isControlFlowException(exception)) {
+                context.addIssue(exceptClause.exceptKeyword(), DESCRIPTION);
+            }
+        }
+    }
+
+    private boolean isControlFlowException(Expression exception) {
+        if (exception.is(Tree.Kind.TUPLE)) {
+            Tuple tuple = (Tuple) exception;
+            for (Expression element : tuple.elements()) {
+                if (isControlFlowException(element)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        
+        String exceptionName = exception.firstToken().value();
+        return CONTROL_FLOW_EXCEPTIONS.contains(exceptionName);
+    }
+}
+
diff --git a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json
index d33223c..86bda65 100644
--- a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json
+++ b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json
@@ -22,6 +22,7 @@
 		"GCI106",
 		"GCI107",
 		"GCI108",
+		"GCI109",
 		"GCI203",
 		"GCI404"
 	]
diff --git a/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidExceptionsForControlFlowCheckTest.java b/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidExceptionsForControlFlowCheckTest.java
new file mode 100644
index 0000000..9fdbcb8
--- /dev/null
+++ b/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidExceptionsForControlFlowCheckTest.java
@@ -0,0 +1,30 @@
+/*
+ * creedengo - Python language - Provides rules to reduce the environmental footprint of your Python programs
+ * Copyright © 2024 Green Code Initiative (https://green-code-initiative.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.greencodeinitiative.creedengo.python.checks;
+
+import org.junit.jupiter.api.Test;
+import org.sonar.python.checks.utils.PythonCheckVerifier;
+
+public class AvoidExceptionsForControlFlowCheckTest {
+
+    @Test
+    public void test() {
+        PythonCheckVerifier.verify("src/test/resources/checks/avoidExceptionsForControlFlow.py", new AvoidExceptionsForControlFlowCheck());
+    }
+}
+
diff --git a/src/test/resources/checks/avoidExceptionsForControlFlow.py b/src/test/resources/checks/avoidExceptionsForControlFlow.py
new file mode 100644
index 0000000..ed483a0
--- /dev/null
+++ b/src/test/resources/checks/avoidExceptionsForControlFlow.py
@@ -0,0 +1,85 @@
+# using KeyError for control flow
+try:
+    value = my_dict[key]
+except KeyError:  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = default
+
+# using IndexError for control flow
+try:
+    item = my_list[index]
+except IndexError:  # Noncompliant {{Avoid using exceptions for control flow}}
+    item = None
+
+# using AttributeError for control flow
+try:
+    value = obj.attribute
+except AttributeError:  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+#  using StopIteration for control flow
+try:
+    value = next(iterator)
+except StopIteration:  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+# KeyError in loop
+for key in keys:
+    try:
+        values.append(my_dict[key])
+    except KeyError:  # Noncompliant {{Avoid using exceptions for control flow}}
+        values.append(default)
+
+# multiple exceptions in tuple 
+try:
+    value = my_dict[key]
+except (KeyError, ValueError):  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+# multiple control flow exceptions in tuple
+try:
+    item = my_list[index]
+except (IndexError, KeyError):  # Noncompliant {{Avoid using exceptions for control flow}}
+    item = None
+
+# AttributeError with other exceptions in tuple
+try:
+    value = obj.attribute
+except (AttributeError, TypeError):  # Noncompliant {{Avoid using exceptions for control flow}}
+    value = None
+
+
+
+### Compliant cases ###
+value = my_dict.get(key, default)
+
+
+
+if 0 <= index < len(my_list):
+    item = my_list[index]
+else:
+    item = None
+
+
+
+value = getattr(obj, 'attribute', None)
+
+
+value = next(iterator, None)
+
+
+try:
+    result = risky_operation()
+except ValueError:
+    result = None
+
+
+
+try:
+    process_file()
+except (IOError, OSError):
+    handle_error()
+
+
+
+for key in keys:
+    values.append(my_dict.get(key, default))