diff --git a/Processes/Sibyll/CMakeLists.txt b/Processes/Sibyll/CMakeLists.txt
index bf89db756b5aaca2be901596c1015b5d724245e7..215685c6c38255f72ae7dd21924d214b1d66d5a1 100644
--- a/Processes/Sibyll/CMakeLists.txt
+++ b/Processes/Sibyll/CMakeLists.txt
@@ -27,6 +27,7 @@ set (
   SibStack.h
   Decay.h
   Interaction.h
+  NuclearInteraction.h
   ${PROJECT_BINARY_DIR}/Processes/Sibyll/Generated.inc
   )
 
diff --git a/Processes/Sibyll/NuclearInteraction.h b/Processes/Sibyll/NuclearInteraction.h
new file mode 100644
index 0000000000000000000000000000000000000000..5f0d29781e1b5260f61cb65ef3a9e25f209f279b
--- /dev/null
+++ b/Processes/Sibyll/NuclearInteraction.h
@@ -0,0 +1,220 @@
+
+/**
+ * (c) Copyright 2018 CORSIKA Project, corsika-project@lists.kit.edu
+ *
+ * See file AUTHORS for a list of contributors.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * Licence version 3 (GPL Version 3). See file LICENSE for a full version of
+ * the license.
+ */
+
+#ifndef _corsika_process_sibyll_nuclearinteraction_h_
+#define _corsika_process_sibyll_nuclearinteraction_h_
+
+#include <corsika/process/InteractionProcess.h>
+
+#include <corsika/environment/Environment.h>
+#include <corsika/environment/NuclearComposition.h>
+#include <corsika/particles/ParticleProperties.h>
+#include <corsika/process/sibyll/ParticleConversion.h>
+#include <corsika/process/sibyll/SibStack.h>
+#include <corsika/process/sibyll/sibyll2.3c.h>
+#include <corsika/random/RNGManager.h>
+#include <corsika/units/PhysicalUnits.h>
+#include <corsika/utl/COMBoost.h>
+
+namespace corsika::process::sibyll {
+
+  class NuclearInteraction : public corsika::process::InteractionProcess<NuclearInteraction> {
+
+    int fCount = 0;
+    int fNucCount = 0;
+
+  public:
+    NuclearInteraction(corsika::environment::Environment const& env)
+        : fEnvironment(env) {}
+    ~NuclearInteraction() {
+      std::cout << "Sibyll::NuclearInteraction n=" << fCount << " Nnuc=" << fNucCount
+                << std::endl;
+    }
+
+    void Init() {
+
+      using corsika::random::RNGManager;
+      using std::cout;
+      using std::endl;
+
+      // initialize hadronic interaction module
+      sibyll_ini_();
+      
+      // initialize nuclib
+      nuc_nuc_ini_();
+    }
+
+    std::tuple<corsika::units::si::CrossSectionType, int> GetCrossSection(
+        const corsika::particles::Code BeamId, const corsika::particles::Code TargetId,
+        const corsika::units::si::HEPEnergyType CoMenergy) {
+      using namespace corsika::units::si;
+      double sigProd, dummy, dum1, dum2, dum3, dum4;
+      double dumdif[3];
+      
+      if(!corsika::particles::IsNucleus(BeamId)){
+	sigProd = std::numeric_limits<double>::infinity();
+	return std::make_tuple(sigProd * 1_mbarn, 1);
+      }
+
+      // TODO: use nuclib to calc. nuclear cross sections
+      // FOR NOW: use proton cross section for nuclei
+      auto const BeamIdToUse = corsika::particles::Proton::GetCode();
+      std::cout << "WARNING: replacing beam nucleus with proton!" << std::endl;
+      
+      const int iBeam = process::sibyll::GetSibyllXSCode(BeamIdToUse);
+      const double dEcm = CoMenergy / 1_GeV;
+      if (corsika::particles::IsNucleus(TargetId)) {
+	const int iTarget = corsika::particles::GetNucleusA(TargetId);
+	if (iTarget > 18 || iTarget == 0)
+	  throw std::runtime_error(
+				   "Sibyll target outside range. Only nuclei with A<18 are allowed.");
+	sib_sigma_hnuc_(iBeam, iTarget, dEcm, sigProd, dummy);
+	return std::make_tuple(sigProd * 1_mbarn, iTarget);
+      } else if (TargetId == corsika::particles::Proton::GetCode()) {
+	sib_sigma_hp_(iBeam, dEcm, dum1, dum2, sigProd, dumdif, dum3, dum4);
+	return std::make_tuple(sigProd * 1_mbarn, 1);
+      } else {
+	throw std::runtime_error("GetCrossSection: no interaction in sibyll possible");
+	// no interaction in sibyll possible, return infinite cross section? or throw?
+	sigProd = std::numeric_limits<double>::infinity();
+	return std::make_tuple(sigProd * 1_mbarn, 0);
+      }
+    }
+
+    template <typename Particle, typename Track>
+    corsika::units::si::GrammageType GetInteractionLength(Particle const& p, Track&) {
+
+      using namespace corsika::units;
+      using namespace corsika::units::si;
+      using namespace corsika::geometry;
+      using std::cout;
+      using std::endl;
+
+      // coordinate system, get global frame of reference
+      CoordinateSystem& rootCS =
+          RootCoordinateSystem::GetInstance().GetRootCoordinateSystem();
+
+      const particles::Code corsikaBeamId = p.GetPID();
+
+      if(!corsika::particles::IsNucleus(corsikaBeamId))
+	// no nuclear interaction
+	return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm);
+
+      // beam particles for sibyll : 1, 2, 3 for p, pi, k
+      // read from cross section code table
+
+      const HEPMassType nucleon_mass = 0.5 * (corsika::particles::Proton::GetMass() +
+					      corsika::particles::Neutron::GetMass());
+
+      // FOR NOW: assume target is at rest
+      MomentumVector pTarget(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
+
+      // total momentum and energy
+      HEPEnergyType Elab = p.GetEnergy() + nucleon_mass;
+      MomentumVector pTotLab(rootCS, {0.0_GeV, 0.0_GeV, 0.0_GeV});
+      pTotLab += p.GetMomentum();
+      pTotLab += pTarget;
+      auto const pTotLabNorm = pTotLab.norm();
+      // calculate cm. energy
+      const HEPEnergyType ECoM = sqrt(
+				      (Elab + pTotLabNorm) * (Elab - pTotLabNorm)); // binomial for numerical accuracy
+
+      std::cout << "NuclearInteraction: LambdaInt: \n"
+		<< " input energy: " << p.GetEnergy() / 1_GeV << endl
+		<< " beam pid:" << p.GetPID() << endl;
+
+      if ( Elab >= 8.5_GeV && ECoM >= 10_GeV) {
+
+	// get target from environment
+	/*
+	  the target should be defined by the Environment,
+	  ideally as full particle object so that the four momenta
+	  and the boosts can be defined..
+	*/
+	const auto currentNode =
+	  fEnvironment.GetUniverse()->GetContainingNode(p.GetPosition());
+	const auto mediumComposition =
+	  currentNode->GetModelProperties().GetNuclearComposition();
+	// determine average interaction length
+	// weighted sum
+	int i = -1;
+	double avgTargetMassNumber = 0.;
+	si::CrossSectionType weightedProdCrossSection = 0_mbarn;
+	// get weights of components from environment/medium
+	const auto w = mediumComposition.GetFractions();
+	// loop over components in medium
+	for (auto const targetId : mediumComposition.GetComponents()) {
+	  i++;
+	  cout << "NuclearInteraction: get interaction length for target: " << targetId << endl;
+
+	  auto const [productionCrossSection, numberOfNucleons] =
+	    GetCrossSection(corsikaBeamId, targetId, ECoM);
+
+	  std::cout << "NuclearInteraction: "
+		    << " IntLength: sibyll return (mb): "
+		    << productionCrossSection / 1_mbarn << std::endl;
+	  weightedProdCrossSection += w[i] * productionCrossSection;
+	  avgTargetMassNumber += w[i] * numberOfNucleons;
+	}
+	cout << "NuclearInteraction: "
+	     << "IntLength: weighted CrossSection (mb): "
+	     << weightedProdCrossSection / 1_mbarn << endl;
+
+	// calculate interaction length in medium
+	GrammageType const int_length =
+	  avgTargetMassNumber * corsika::units::constants::u / weightedProdCrossSection;
+	std::cout << "NuclearInteraction: "
+		  << "interaction length (g/cm2): "
+		  << int_length / (0.001_kg) * 1_cm * 1_cm << std::endl;
+
+	return int_length;
+      } else {
+	return std::numeric_limits<double>::infinity() * 1_g / (1_cm * 1_cm);
+      }
+    }
+   
+    template <typename Particle, typename Stack>
+    corsika::process::EProcessReturn DoInteraction(Particle& p, Stack& s) {
+
+      using namespace corsika::units;
+      using namespace corsika::utl;
+      using namespace corsika::units::si;
+      using namespace corsika::geometry;
+      using std::cout;
+      using std::endl;
+
+      const auto corsikaBeamId = p.GetPID();
+      const auto kNucleus = IsNucleus(corsikaBeamId);
+      if(!kNucleus)
+	return process::EProcessReturn::eOk;
+      
+
+      // add proton instead
+      auto pnew = s.NewParticle();
+      pnew.SetPID( corsika::particles::Proton::GetCode() );
+      pnew.SetMomentum( p.GetMomentum() );
+      pnew.SetEnergy( p.GetEnergy() );	
+
+      // delete current particle
+      p.Delete();
+
+      return process::EProcessReturn::eOk;
+    }
+
+  private:
+    corsika::environment::Environment const& fEnvironment;
+    corsika::random::RNG& fRNG =
+        corsika::random::RNGManager::GetInstance().GetRandomStream("s_rndm");
+  };
+
+} // namespace corsika::process::sibyll
+
+#endif
diff --git a/Processes/Sibyll/sibyll2.3c.h b/Processes/Sibyll/sibyll2.3c.h
index 104b55eb0bf2e6fc12277f6d62bf1adcf567acb4..cd13ebb67bc9642310f6cf95f8194d6fc6b551f5 100644
--- a/Processes/Sibyll/sibyll2.3c.h
+++ b/Processes/Sibyll/sibyll2.3c.h
@@ -79,6 +79,9 @@ void sibyll_(const int&, const int&, const double&);
 // subroutine to initiate sibyll
 void sibyll_ini_();
 
+// subroutine to initiate nuclib  
+void nuc_nuc_ini_();
+  
 // subroutine to SET DECAYS
 void dec_ini_();
 
diff --git a/Processes/Sibyll/testSibyll.cc b/Processes/Sibyll/testSibyll.cc
index 9b078fd087c16d6238837ce26783468640777054..16449b87c96f57f9eba63c92f4aa30973b597978 100644
--- a/Processes/Sibyll/testSibyll.cc
+++ b/Processes/Sibyll/testSibyll.cc
@@ -11,6 +11,7 @@
 
 #include <corsika/process/sibyll/Decay.h>
 #include <corsika/process/sibyll/Interaction.h>
+#include <corsika/process/sibyll/NuclearInteraction.h>
 #include <corsika/process/sibyll/ParticleConversion.h>
 
 #include <corsika/random/RNGManager.h>
@@ -127,6 +128,20 @@ TEST_CASE("SibyllInterface", "[processes]") {
         model.GetInteractionLength(particle, track);
   }
 
+  SECTION("NuclearInteractionInterface") {
+
+    setup::Stack stack;
+    auto particle = stack.NewParticle();
+
+    Interaction model(env);
+
+    model.Init();
+    [[maybe_unused]] const process::EProcessReturn ret =
+        model.DoInteraction(particle, stack);
+    [[maybe_unused]] const GrammageType length =
+        model.GetInteractionLength(particle, track);
+  }
+
   SECTION("DecayInterface") {
 
     setup::Stack stack;